diff --git a/.ipynb_checkpoints/band_structure_visualization-checkpoint.ipynb b/.ipynb_checkpoints/band_structure_visualization-checkpoint.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..b2c4549632725c1ee3c50a465af06e961f44b6c1
--- /dev/null
+++ b/.ipynb_checkpoints/band_structure_visualization-checkpoint.ipynb
@@ -0,0 +1,4968 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "init_cell": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<style>.container { width:100% !important; }</style>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "from IPython.core.display import display, HTML\n",
+    "display(HTML(\"<style>.container { width:100% !important; }</style>\"))\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "init_cell": true
+   },
+   "outputs": [],
+   "source": [
+    "from IPython.core.display import Javascript\n",
+    "from IPython.display import display\n",
+    "\n",
+    "def run_cell_by_tag(tags):\n",
+    "    display(Javascript(\"window.runCells('\"+tags+\"')\"))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "init_cell": true,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "    code_show=true; \n",
+       "    function code_toggle() {\n",
+       "        if (code_show)\n",
+       "        {\n",
+       "            $('div.input').hide();\n",
+       "        } \n",
+       "        else \n",
+       "        {\n",
+       "            $('div.input').show();\n",
+       "        }\n",
+       "        code_show = !code_show\n",
+       "    } \n",
+       "    $( document ).ready(code_toggle);\n",
+       "</script>\n",
+       "The raw code for this notebook is by default hidden for easier reading.\n",
+       "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>.\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "    code_show=true; \n",
+    "    function code_toggle() {\n",
+    "        if (code_show)\n",
+    "        {\n",
+    "            $('div.input').hide();\n",
+    "        } \n",
+    "        else \n",
+    "        {\n",
+    "            $('div.input').show();\n",
+    "        }\n",
+    "        code_show = !code_show\n",
+    "    } \n",
+    "    $( document ).ready(code_toggle);\n",
+    "</script>\n",
+    "The raw code for this notebook is by default hidden for easier reading.\n",
+    "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "init_cell": true,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "\n",
+       "<div align=\"left\" style=\"background-color: rgba(149,170,79, 1.0); width: 100%; height: 390px; overflow: hidden;\">\n",
+       "    <div >\n",
+       "        <table>\n",
+       "            <tr></tr>\n",
+       "            <tr>\n",
+       "                <td><img src=\"Nomad_tutorial_head.png\"></td>\n",
+       "            </tr>\n",
+       "        </table>\n",
+       "    </div>\n",
+       "\n",
+       "    <br><br>\n",
+       "    <div style=\"position:relative; left:3%\"><font size=6em  color=\"#20335d\" ><b> -  Visualization of the band structure of materials </b></font></div>\n",
+       "    <p style=\"position:relative;left:10%; \">\n",
+       "        <br>\n",
+       "        Created by:\n",
+       "\n",
+       "        Xiangyue Liu<sup>1</sup>(<a href=\"mailto:xyliu@fhi-berlin.mpg.de\">email</a>),\n",
+       "        \n",
+       "        Fawzi Mohamed<sup>1</sup>,\n",
+       "        \n",
+       "        and Luca M. Ghiringhelli<sup>1</sup>(<a href=\"mailto:ghiringhelli@fhi-berlin.mpg.de\">email</a>), <br>\n",
+       "\n",
+       "        <br><br>\n",
+       "        <sup>1</sup> Fritz Haber Institute of the Max Planck Society, Faradayweg 4-6, D-14195 Berlin, Germany <br>\n",
+       "        <br>\n",
+       "\n",
+       "\n",
+       "    </p>\n",
+       "    <br>\n",
+       "    <div style=\"position:relative;bottom:3%\">\n",
+       "        <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#999999\" size=\"10em\">v2.0.0</font></div>\n",
+       "        <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#666666\" size=\"2.7em\">[Last updated: August 5, 2019]</font></div>\n",
+       "    </div>\n",
+       "\n",
+       "</div>\n",
+       "\n",
+       "\n",
+       "<div style='text-align: right;'>\n",
+       "    <a href=\"https://analytics-toolkit.nomad-coe.eu/home/\" class=\"btn btn-primary\" style=\"font-size:larger;\">Back to Analytics Home</a> \n",
+       "    <a href=\"https://www.nomad-coe.eu/\" class=\"btn btn-primary\" style=\"font-size:larger; \">Back to nomad-coe</a> \n",
+       "</div>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "\n",
+    "\n",
+    "<div align=\"left\" style=\"background-color: rgba(149,170,79, 1.0); width: 100%; height: 390px; overflow: hidden;\">\n",
+    "    <div >\n",
+    "        <table>\n",
+    "            <tr></tr>\n",
+    "            <tr>\n",
+    "                <td><img src=\"Nomad_tutorial_head.png\"></td>\n",
+    "            </tr>\n",
+    "        </table>\n",
+    "    </div>\n",
+    "\n",
+    "    <br><br>\n",
+    "    <div style=\"position:relative; left:3%\"><font size=6em  color=\"#20335d\" ><b> -  Visualization of the band structure of materials </b></font></div>\n",
+    "    <p style=\"position:relative;left:10%; \">\n",
+    "        <br>\n",
+    "        Created by:\n",
+    "\n",
+    "        Xiangyue Liu<sup>1</sup>(<a href=\"mailto:xyliu@fhi-berlin.mpg.de\">email</a>),\n",
+    "        \n",
+    "        Fawzi Mohamed<sup>1</sup>,\n",
+    "        \n",
+    "        and Luca M. Ghiringhelli<sup>1</sup>(<a href=\"mailto:ghiringhelli@fhi-berlin.mpg.de\">email</a>), <br>\n",
+    "\n",
+    "        <br><br>\n",
+    "        <sup>1</sup> Fritz Haber Institute of the Max Planck Society, Faradayweg 4-6, D-14195 Berlin, Germany <br>\n",
+    "        <br>\n",
+    "\n",
+    "\n",
+    "    </p>\n",
+    "    <br>\n",
+    "    <div style=\"position:relative;bottom:3%\">\n",
+    "        <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#999999\" size=\"10em\">v2.0.0</font></div>\n",
+    "        <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#666666\" size=\"2.7em\">[Last updated: August 5, 2019]</font></div>\n",
+    "    </div>\n",
+    "\n",
+    "</div>\n",
+    "\n",
+    "\n",
+    "<div style='text-align: right;'>\n",
+    "    <a href=\"https://analytics-toolkit.nomad-coe.eu/home/\" class=\"btn btn-primary\" style=\"font-size:larger;\">Back to Analytics Home</a> \n",
+    "    <a href=\"https://www.nomad-coe.eu/\" class=\"btn btn-primary\" style=\"font-size:larger; \">Back to nomad-coe</a> \n",
+    "</div>\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "init_cell": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "    window.findCellIndicesByTag = function findCellIndicesByTag(tagName) {\n",
+       "      return (Jupyter.notebook.get_cells()\n",
+       "        .filter(\n",
+       "          ({metadata: {tags}}) => tags && tags.includes(tagName)\n",
+       "        )\n",
+       "        .map((cell) => Jupyter.notebook.find_cell_index(cell))\n",
+       "      );\n",
+       "    };\n",
+       "\n",
+       "\n",
+       "    window.runCells = function runPlotCells(tags) {\n",
+       "        var c = window.findCellIndicesByTag(tags);\n",
+       "        Jupyter.notebook.execute_cells(c);\n",
+       "    };\n",
+       "</script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "    window.findCellIndicesByTag = function findCellIndicesByTag(tagName) {\n",
+    "      return (Jupyter.notebook.get_cells()\n",
+    "        .filter(\n",
+    "          ({metadata: {tags}}) => tags && tags.includes(tagName)\n",
+    "        )\n",
+    "        .map((cell) => Jupyter.notebook.find_cell_index(cell))\n",
+    "      );\n",
+    "    };\n",
+    "\n",
+    "\n",
+    "    window.runCells = function runPlotCells(tags) {\n",
+    "        var c = window.findCellIndicesByTag(tags);\n",
+    "        Jupyter.notebook.execute_cells(c);\n",
+    "    };\n",
+    "</script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 53,
+   "metadata": {
+    "init_cell": true,
+    "tags": [
+     "search_materials"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<br><br>\n",
+       "\n",
+       "<p style=\"color: #20335d;font-weight: 450; font-size: 14pt;font-family: Arial;\"> This tutorial visulizes the band structures and density of states (DOS) of the NOMAD materials.</p>\n",
+       "<br><br>\n",
+       "\n",
+       "<style>\n",
+       ".button {\n",
+       "    background-color: #e7e7e7;\n",
+       "    border: 0.5px solid #A4A4A4;\n",
+       "    color: black;\n",
+       "    padding: 15px 32px;\n",
+       "    text-align: center;\n",
+       "    text-decoration: none;\n",
+       "    display: inline-block;\n",
+       "    font-family: Arial;\n",
+       "    font-size: 16px;\n",
+       "    margin: 4px 2px;\n",
+       "    cursor: pointer;\n",
+       "}\n",
+       "\n",
+       "  .text-normal-black{\n",
+       "    color: #000;font-weight: 200; font-size: 10pt;\n",
+       "    font-family: Arial;\n",
+       "  }\n",
+       "  .div_band_dos{\n",
+       "    box-sizing: border-box;\n",
+       "    width: 100%;\n",
+       "    height: 600px;\n",
+       "    font-weight: 100;\n",
+       "    font-family: Arial;\n",
+       "    padding-left: 20px;\n",
+       "    padding-top: 10px;\n",
+       "    padding-right: 1em;\n",
+       "    margin: 0;\n",
+       "    border: 0;\n",
+       "  }\n",
+       "  .div_band_dos_compare{\n",
+       "    box-sizing: border-box;\n",
+       "    width: 1600px;\n",
+       "    height: 600px;\n",
+       "    color: #00AEFF;\n",
+       "    font-weight: 100;\n",
+       "    font-family: Arial;\n",
+       "    padding-left: 20px;\n",
+       "    padding-top: 10px;\n",
+       "    padding-right: 1em;\n",
+       "    margin: 0;\n",
+       "    border: 0;\n",
+       "  }\n",
+       "  .div_band{\n",
+       "    font-family: Arial;\n",
+       "    font-size: 0.875em;\n",
+       "    width: 37%;\n",
+       "    height: 80%;\n",
+       "    background-color: #fff;\n",
+       "    float:left;\n",
+       "  }\n",
+       "  .div_dos{\n",
+       "    font-family: Arial;\n",
+       "    font-size: 0.875em;\n",
+       "    width: 13%;\n",
+       "    height: 80%;\n",
+       "    background-color: #fff;\n",
+       "    float:left;\n",
+       "  }\n",
+       "  .div_tools{\n",
+       "    color: #20335d;font-weight: 150; font-size: 13pt;\n",
+       "    width: 35%;\n",
+       "    height: 80%;\n",
+       "    background-color: #fff;\n",
+       "    margin-left:20pt;\n",
+       "    float:left;\n",
+       "    font-family: Arial;\n",
+       "\n",
+       "  }\n",
+       "  .div_checkbox_compare{\n",
+       "    color: #888;font-weight: 150; font-size: 12pt;\n",
+       "    width: 10%;\n",
+       "    height: 80%;\n",
+       "    background-color: #fff;\n",
+       "    border: solid #fff 1px;\n",
+       "    float:right;\n",
+       "    font-family: Arial;\n",
+       "\n",
+       "  }\n",
+       "  .div_overview{\n",
+       "    width: 300px;\n",
+       "    height: 200px;\n",
+       "    background-color: #fff;\n",
+       "    margin-left:10px; \n",
+       "    margin-top: 20px;\n",
+       "    font-family: Arial;\n",
+       "\n",
+       "  }\n",
+       "  .button_tools {\n",
+       "    background-color: #F0F0F0;\n",
+       "    border: 0.5px solid #A4A4A4;\n",
+       "    color: black;\n",
+       "    padding: 10px 15px;\n",
+       "    text-align: center;\n",
+       "    text-decoration: none;\n",
+       "    display: inline-block;\n",
+       "    font-size: 16px;\n",
+       "    margin: 4px 2px;\n",
+       "    cursor: pointer;\n",
+       "    font-family: Arial;\n",
+       "\n",
+       "  }\n",
+       "\n",
+       "  \n",
+       "  .g-before-after{position:relative;overflow:hidden;width:500px}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%}\n",
+       "</style>\n",
+       "\n",
+       "<script>\n",
+       "    //Search for certain keyword: https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\n",
+       "    //FjiYy5-ETRCrs5ktzJA55w/bOY0cPkBvvNAY7pZdbginlKXJ2kF\n",
+       "    //\"upload_id\"/\"calc_id\"\n",
+       "    \n",
+       "    //Global variables\n",
+       "    var paths_section_k_band_segment = []; \n",
+       "    var paths_section_dos = [];\n",
+       "    var band_obj_all = [];\n",
+       "    var dos_obj_all = [];\n",
+       "    var info_obj_all = [];\n",
+       "    \n",
+       "    var band_paths = [];\n",
+       "    var dos_paths = [];\n",
+       "    var N_materials = 0;  //Number of materials that have both band and DOS in the same calculation   \n",
+       "    \n",
+       "    \n",
+       "    function getJSON(url) {\n",
+       "        var resp ;\n",
+       "        var xmlHttp ;\n",
+       "\n",
+       "        resp  = '' ;\n",
+       "        xmlHttp = new XMLHttpRequest();\n",
+       "\n",
+       "        if(xmlHttp != null)\n",
+       "        {\n",
+       "            xmlHttp.open( \"GET\", url, false );\n",
+       "            xmlHttp.send( null );\n",
+       "            resp = xmlHttp.responseText;\n",
+       "        }\n",
+       "\n",
+       "        return resp;\n",
+       "    }\n",
+       "    function match_band_dos()\n",
+       "    {\n",
+       "        //TMP for local tests\n",
+       "        /*\n",
+       "        paths_section_k_band_segment = [\"data/kOJR-AlPSgiNG9AdZoxd4g_9mxjIU0edrPosfsTc4uyDG9H_UXr.json\",\"data/kOJR-AlPSgiNG9AdZoxd4g_lfkGCmWozYENeiGhu5W7dJUqLTkj.json\"];\n",
+       "        paths_section_dos = [\"data/kOJR-AlPSgiNG9AdZoxd4g_8tEGnaz0yY91eSyysKZkIUH9qx8J.json\", \"data/kOJR-AlPSgiNG9AdZoxd4g_lxUT3viRZcC_1IsH_KvO5tChAtV1.json\"];\n",
+       "        */\n",
+       "\n",
+       "        //band_paths = [];\n",
+       "        //dos_paths = [];\n",
+       "        //N_materials = 0;    \n",
+       "        \n",
+       "        var data_k_band = [];\n",
+       "        for(var i_path_k_band = 0; i_path_k_band < paths_section_k_band_segment.length; i_path_k_band ++)\n",
+       "        {\n",
+       "            var i_data_k_band_json = JSON.parse(getJSON(paths_section_k_band_segment[i_path_k_band]));\n",
+       "            var i_data_k_band = {};\n",
+       "            i_data_k_band[\"program_name\"] = i_data_k_band_json[\"section_run\"][\"program_name\"];\n",
+       "            i_data_k_band[\"k_mesh_points\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n",
+       "            i_data_k_band[\"simulation_cell\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n",
+       "            i_data_k_band[\"atom_positions\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n",
+       "            i_data_k_band[\"atom_labels\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+       "            i_data_k_band[\"XC_functional_name\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n",
+       "            i_data_k_band[\"path\"] = paths_section_k_band_segment[i_path_k_band];\n",
+       "            data_k_band.push(i_data_k_band);\n",
+       "        }\n",
+       "\n",
+       "        var data_dos = [];\n",
+       "        for(var i_path_dos = 0; i_path_dos < paths_section_dos.length; i_path_dos ++)\n",
+       "        {\n",
+       "            var i_data_dos_json = JSON.parse(getJSON(paths_section_dos[i_path_dos]));\n",
+       "            var i_data_dos = {};\n",
+       "            i_data_dos[\"program_name\"] = i_data_dos_json[\"section_run\"][\"program_name\"];\n",
+       "            i_data_dos[\"k_mesh_points\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n",
+       "            i_data_dos[\"simulation_cell\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n",
+       "            i_data_dos[\"atom_positions\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n",
+       "            i_data_dos[\"atom_labels\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+       "            i_data_dos[\"XC_functional_name\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n",
+       "            i_data_dos[\"path\"] = paths_section_dos[i_path_dos];\n",
+       "            data_dos.push(i_data_dos);       \n",
+       "        }\n",
+       "\n",
+       "        //Matching: band[i] ~ dos[i]  (the same systems are arranged with the same index)\n",
+       "        band_paths = [];\n",
+       "        dos_paths = [];\n",
+       "        N_materials = 0;\n",
+       "        for(var i_k_band = 0; i_k_band < data_k_band.length; i_k_band ++)\n",
+       "        {\n",
+       "            for(var i_dos = 0; i_dos < data_dos.length; i_dos ++)\n",
+       "            {\n",
+       "                if(data_k_band[i_k_band][\"program_name\"] != data_dos[i_dos][\"program_name\"])\n",
+       "                    continue;        \n",
+       "                //if(data_k_band[i_k_band][\"k_mesh_points\"].join() != data_dos[i_dos][\"k_mesh_points\"].join())\n",
+       "                //   continue;\n",
+       "                if(data_k_band[i_k_band][\"simulation_cell\"].join() != data_dos[i_dos][\"simulation_cell\"].join())\n",
+       "                    continue;\n",
+       "                if(data_k_band[i_k_band][\"atom_positions\"].join() != data_dos[i_dos][\"atom_positions\"].join())\n",
+       "                    continue;\n",
+       "                if(data_k_band[i_k_band][\"atom_labels\"].join() != data_dos[i_dos][\"atom_labels\"].join())\n",
+       "                    continue;\n",
+       "                if(data_k_band[i_k_band][\"XC_functional_name\"] != data_dos[i_dos][\"XC_functional_name\"])\n",
+       "                    continue;\n",
+       "                band_paths.push(data_k_band[i_k_band][\"path\"]);\n",
+       "                dos_paths.push(data_dos[i_dos][\"path\"]);\n",
+       "                N_materials ++;\n",
+       "            }\n",
+       "        }\n",
+       "        //Pass the arrays to python\n",
+       "\n",
+       "        var command = \"N_materials = \" + N_materials + \";\"\n",
+       "        var kernel = IPython.notebook.kernel;\n",
+       "        command += \"band_paths = \" + \"[\\'\" + band_paths.join(\"\\',\\'\") + \"\\'];\";\n",
+       "        command += \"dos_paths = \" + \"[\\'\" + dos_paths.join(\"\\',\\'\") + \"\\'];\";\n",
+       "        kernel.execute(command);\n",
+       "        \n",
+       "        \n",
+       "    }\n",
+       "\n",
+       "    function get_paths_from_search_results(result_json, div_id_search_results,div_head)\n",
+       "    {\n",
+       "        paths = [];\n",
+       "        search_results_content = [div_head, '<table>', '<tr><th>Chemical formula</th><th>Spacegroup</th><th>Code</th><th>XC functional</th><th>Upload ID</th><th>Calculation ID</th><th>URL</th></tr>'];\n",
+       "        for(var i_key in result_json)\n",
+       "        {\n",
+       "            if(i_key == \"results\")\n",
+       "            {\n",
+       "                for(var system in result_json[i_key])\n",
+       "                {\n",
+       "                    //Get the path to the data files (json): https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/upload_id/calc_id \n",
+       "                    path = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/\" + result_json[i_key][system][\"upload_id\"] + \"/\" + result_json[i_key][system][\"calc_id\"]\n",
+       "                    paths.push(path);\n",
+       "                    \n",
+       "                    //Show the results in div\n",
+       "                    // \"formula\" \"spacegroup_symbol\" \"code_name\" \"xc_functional\"\n",
+       "                    content = '<tr>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"formula\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"spacegroup_symbol\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"code_name\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"xc_functional\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"upload_id\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"calc_id\"] + '</td>';                    \n",
+       "                    content += '<td>' + path + '</td>';\n",
+       "                    content += '</tr>';\n",
+       "                    search_results_content.push(content);\n",
+       "                }\n",
+       "            }\n",
+       "        }\n",
+       "        search_results_content.push('</table>');\n",
+       "        document.getElementById(div_id_search_results).innerHTML = search_results_content.join('');\n",
+       "        return paths\n",
+       "    }\n",
+       "    \n",
+       "    \n",
+       "    \n",
+       "\n",
+       "    \n",
+       "    \n",
+       "    \n",
+       "    function submit_search()\n",
+       "    {\n",
+       "        \n",
+       "        var result;\n",
+       "        var formula = document.getElementById(\"keyword_chemical_formula\").value;\n",
+       "        var query_command_k_band = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_k_band_segment\";\n",
+       "        var query_command_dos =  \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_dos\";\n",
+       "        //result = getJSON(\"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\");\n",
+       "        var result_k_band = getJSON(query_command_k_band);\n",
+       "        var result_dos = getJSON(query_command_dos);\n",
+       "        var result_json_k_band = JSON.parse(result_k_band);//parse the searching results to json from URL\n",
+       "        var result_json_dos = JSON.parse(result_dos);\n",
+       "        paths_section_k_band_segment = []; \n",
+       "        paths_section_dos = [];\n",
+       "        paths_section_k_band_segment = get_paths_from_search_results(result_json_k_band, \"search_results_section_k_band_segment\", \"<br><br><font size=4em>Calculations containing band structures:</font><br>\");\n",
+       "        paths_section_dos = get_paths_from_search_results(result_json_dos, \"search_results_section_dos\", \"<br><font size=4em>Calculations containing DOS:</font><br>\");\n",
+       "     \n",
+       "        var promise = Promise.resolve();\n",
+       "        promise\n",
+       "            .then(match_band_dos())\n",
+       "            .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')))\n",
+       "            .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')));\n",
+       "        \n",
+       "        //match_band_dos();\n",
+       "              \n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')); //Read the json files, and prepare data for plot\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')); //Prepare for plot\n",
+       "    }\n",
+       "    function reset_search()\n",
+       "    {\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('search_materials'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot'));\n",
+       "    }\n",
+       "    \n",
+       "    \n",
+       "</script>\n",
+       "<font size=4em>Please input the chemical formula:</font>\n",
+       "<input type=\"text\" id=\"keyword_chemical_formula\" value=\"AlInO3\"> \n",
+       "<button class=\"button\" onclick=\"submit_search()\">Search</button>\n",
+       "<button class=\"button\" onclick=\"reset_search()\">Reset</button>\n",
+       "<br><br><br>\n",
+       "<div id=\"search_results_section_k_band_segment\"></div>\n",
+       "<div id=\"search_results_section_dos\"></div>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%html\n",
+    "<br><br>\n",
+    "\n",
+    "<p style=\"color: #20335d;font-weight: 450; font-size: 14pt;font-family: Arial;\"> This tutorial visulizes the band structures and density of states (DOS) of the NOMAD materials.</p>\n",
+    "<br><br>\n",
+    "\n",
+    "<style>\n",
+    ".button {\n",
+    "    background-color: #e7e7e7;\n",
+    "    border: 0.5px solid #A4A4A4;\n",
+    "    color: black;\n",
+    "    padding: 15px 32px;\n",
+    "    text-align: center;\n",
+    "    text-decoration: none;\n",
+    "    display: inline-block;\n",
+    "    font-family: Arial;\n",
+    "    font-size: 16px;\n",
+    "    margin: 4px 2px;\n",
+    "    cursor: pointer;\n",
+    "}\n",
+    "\n",
+    "  .text-normal-black{\n",
+    "    color: #000;font-weight: 200; font-size: 10pt;\n",
+    "    font-family: Arial;\n",
+    "  }\n",
+    "  .div_band_dos{\n",
+    "    box-sizing: border-box;\n",
+    "    width: 100%;\n",
+    "    height: 600px;\n",
+    "    font-weight: 100;\n",
+    "    font-family: Arial;\n",
+    "    padding-left: 20px;\n",
+    "    padding-top: 10px;\n",
+    "    padding-right: 1em;\n",
+    "    margin: 0;\n",
+    "    border: 0;\n",
+    "  }\n",
+    "  .div_band_dos_compare{\n",
+    "    box-sizing: border-box;\n",
+    "    width: 1600px;\n",
+    "    height: 600px;\n",
+    "    color: #00AEFF;\n",
+    "    font-weight: 100;\n",
+    "    font-family: Arial;\n",
+    "    padding-left: 20px;\n",
+    "    padding-top: 10px;\n",
+    "    padding-right: 1em;\n",
+    "    margin: 0;\n",
+    "    border: 0;\n",
+    "  }\n",
+    "  .div_band{\n",
+    "    font-family: Arial;\n",
+    "    font-size: 0.875em;\n",
+    "    width: 37%;\n",
+    "    height: 80%;\n",
+    "    background-color: #fff;\n",
+    "    float:left;\n",
+    "  }\n",
+    "  .div_dos{\n",
+    "    font-family: Arial;\n",
+    "    font-size: 0.875em;\n",
+    "    width: 13%;\n",
+    "    height: 80%;\n",
+    "    background-color: #fff;\n",
+    "    float:left;\n",
+    "  }\n",
+    "  .div_tools{\n",
+    "    color: #20335d;font-weight: 150; font-size: 13pt;\n",
+    "    width: 35%;\n",
+    "    height: 80%;\n",
+    "    background-color: #fff;\n",
+    "    margin-left:20pt;\n",
+    "    float:left;\n",
+    "    font-family: Arial;\n",
+    "\n",
+    "  }\n",
+    "  .div_checkbox_compare{\n",
+    "    color: #888;font-weight: 150; font-size: 12pt;\n",
+    "    width: 10%;\n",
+    "    height: 80%;\n",
+    "    background-color: #fff;\n",
+    "    border: solid #fff 1px;\n",
+    "    float:right;\n",
+    "    font-family: Arial;\n",
+    "\n",
+    "  }\n",
+    "  .div_overview{\n",
+    "    width: 300px;\n",
+    "    height: 200px;\n",
+    "    background-color: #fff;\n",
+    "    margin-left:10px; \n",
+    "    margin-top: 20px;\n",
+    "    font-family: Arial;\n",
+    "\n",
+    "  }\n",
+    "  .button_tools {\n",
+    "    background-color: #F0F0F0;\n",
+    "    border: 0.5px solid #A4A4A4;\n",
+    "    color: black;\n",
+    "    padding: 10px 15px;\n",
+    "    text-align: center;\n",
+    "    text-decoration: none;\n",
+    "    display: inline-block;\n",
+    "    font-size: 16px;\n",
+    "    margin: 4px 2px;\n",
+    "    cursor: pointer;\n",
+    "    font-family: Arial;\n",
+    "\n",
+    "  }\n",
+    "\n",
+    "  \n",
+    "  .g-before-after{position:relative;overflow:hidden;width:500px}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%}\n",
+    "</style>\n",
+    "\n",
+    "<script>\n",
+    "    //Search for certain keyword: https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\n",
+    "    //FjiYy5-ETRCrs5ktzJA55w/bOY0cPkBvvNAY7pZdbginlKXJ2kF\n",
+    "    //\"upload_id\"/\"calc_id\"\n",
+    "    \n",
+    "    //Global variables\n",
+    "    var paths_section_k_band_segment = []; \n",
+    "    var paths_section_dos = [];\n",
+    "    var band_obj_all = [];\n",
+    "    var dos_obj_all = [];\n",
+    "    var info_obj_all = [];\n",
+    "    \n",
+    "    var band_paths = [];\n",
+    "    var dos_paths = [];\n",
+    "    var N_materials = 0;  //Number of materials that have both band and DOS in the same calculation   \n",
+    "    \n",
+    "    \n",
+    "    function getJSON(url) {\n",
+    "        var resp ;\n",
+    "        var xmlHttp ;\n",
+    "\n",
+    "        resp  = '' ;\n",
+    "        xmlHttp = new XMLHttpRequest();\n",
+    "\n",
+    "        if(xmlHttp != null)\n",
+    "        {\n",
+    "            xmlHttp.open( \"GET\", url, false );\n",
+    "            xmlHttp.send( null );\n",
+    "            resp = xmlHttp.responseText;\n",
+    "        }\n",
+    "\n",
+    "        return resp;\n",
+    "    }\n",
+    "    function match_band_dos()\n",
+    "    {\n",
+    "        //TMP for local tests\n",
+    "        /*\n",
+    "        paths_section_k_band_segment = [\"data/kOJR-AlPSgiNG9AdZoxd4g_9mxjIU0edrPosfsTc4uyDG9H_UXr.json\",\"data/kOJR-AlPSgiNG9AdZoxd4g_lfkGCmWozYENeiGhu5W7dJUqLTkj.json\"];\n",
+    "        paths_section_dos = [\"data/kOJR-AlPSgiNG9AdZoxd4g_8tEGnaz0yY91eSyysKZkIUH9qx8J.json\", \"data/kOJR-AlPSgiNG9AdZoxd4g_lxUT3viRZcC_1IsH_KvO5tChAtV1.json\"];\n",
+    "        */\n",
+    "\n",
+    "        //band_paths = [];\n",
+    "        //dos_paths = [];\n",
+    "        //N_materials = 0;    \n",
+    "        \n",
+    "        var data_k_band = [];\n",
+    "        for(var i_path_k_band = 0; i_path_k_band < paths_section_k_band_segment.length; i_path_k_band ++)\n",
+    "        {\n",
+    "            var i_data_k_band_json = JSON.parse(getJSON(paths_section_k_band_segment[i_path_k_band]));\n",
+    "            var i_data_k_band = {};\n",
+    "            i_data_k_band[\"program_name\"] = i_data_k_band_json[\"section_run\"][\"program_name\"];\n",
+    "            i_data_k_band[\"k_mesh_points\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n",
+    "            i_data_k_band[\"simulation_cell\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n",
+    "            i_data_k_band[\"atom_positions\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n",
+    "            i_data_k_band[\"atom_labels\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+    "            i_data_k_band[\"XC_functional_name\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n",
+    "            i_data_k_band[\"path\"] = paths_section_k_band_segment[i_path_k_band];\n",
+    "            data_k_band.push(i_data_k_band);\n",
+    "        }\n",
+    "\n",
+    "        var data_dos = [];\n",
+    "        for(var i_path_dos = 0; i_path_dos < paths_section_dos.length; i_path_dos ++)\n",
+    "        {\n",
+    "            var i_data_dos_json = JSON.parse(getJSON(paths_section_dos[i_path_dos]));\n",
+    "            var i_data_dos = {};\n",
+    "            i_data_dos[\"program_name\"] = i_data_dos_json[\"section_run\"][\"program_name\"];\n",
+    "            i_data_dos[\"k_mesh_points\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n",
+    "            i_data_dos[\"simulation_cell\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n",
+    "            i_data_dos[\"atom_positions\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n",
+    "            i_data_dos[\"atom_labels\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+    "            i_data_dos[\"XC_functional_name\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n",
+    "            i_data_dos[\"path\"] = paths_section_dos[i_path_dos];\n",
+    "            data_dos.push(i_data_dos);       \n",
+    "        }\n",
+    "\n",
+    "        //Matching: band[i] ~ dos[i]  (the same systems are arranged with the same index)\n",
+    "        band_paths = [];\n",
+    "        dos_paths = [];\n",
+    "        N_materials = 0;\n",
+    "        for(var i_k_band = 0; i_k_band < data_k_band.length; i_k_band ++)\n",
+    "        {\n",
+    "            for(var i_dos = 0; i_dos < data_dos.length; i_dos ++)\n",
+    "            {\n",
+    "                if(data_k_band[i_k_band][\"program_name\"] != data_dos[i_dos][\"program_name\"])\n",
+    "                    continue;        \n",
+    "                //if(data_k_band[i_k_band][\"k_mesh_points\"].join() != data_dos[i_dos][\"k_mesh_points\"].join())\n",
+    "                //   continue;\n",
+    "                if(data_k_band[i_k_band][\"simulation_cell\"].join() != data_dos[i_dos][\"simulation_cell\"].join())\n",
+    "                    continue;\n",
+    "                if(data_k_band[i_k_band][\"atom_positions\"].join() != data_dos[i_dos][\"atom_positions\"].join())\n",
+    "                    continue;\n",
+    "                if(data_k_band[i_k_band][\"atom_labels\"].join() != data_dos[i_dos][\"atom_labels\"].join())\n",
+    "                    continue;\n",
+    "                if(data_k_band[i_k_band][\"XC_functional_name\"] != data_dos[i_dos][\"XC_functional_name\"])\n",
+    "                    continue;\n",
+    "                band_paths.push(data_k_band[i_k_band][\"path\"]);\n",
+    "                dos_paths.push(data_dos[i_dos][\"path\"]);\n",
+    "                N_materials ++;\n",
+    "            }\n",
+    "        }\n",
+    "        //Pass the arrays to python\n",
+    "\n",
+    "        var command = \"N_materials = \" + N_materials + \";\"\n",
+    "        var kernel = IPython.notebook.kernel;\n",
+    "        command += \"band_paths = \" + \"[\\'\" + band_paths.join(\"\\',\\'\") + \"\\'];\";\n",
+    "        command += \"dos_paths = \" + \"[\\'\" + dos_paths.join(\"\\',\\'\") + \"\\'];\";\n",
+    "        kernel.execute(command);\n",
+    "        \n",
+    "        \n",
+    "    }\n",
+    "\n",
+    "    function get_paths_from_search_results(result_json, div_id_search_results,div_head)\n",
+    "    {\n",
+    "        paths = [];\n",
+    "        search_results_content = [div_head, '<table>', '<tr><th>Chemical formula</th><th>Spacegroup</th><th>Code</th><th>XC functional</th><th>Upload ID</th><th>Calculation ID</th><th>URL</th></tr>'];\n",
+    "        for(var i_key in result_json)\n",
+    "        {\n",
+    "            if(i_key == \"results\")\n",
+    "            {\n",
+    "                for(var system in result_json[i_key])\n",
+    "                {\n",
+    "                    //Get the path to the data files (json): https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/upload_id/calc_id \n",
+    "                    path = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/\" + result_json[i_key][system][\"upload_id\"] + \"/\" + result_json[i_key][system][\"calc_id\"]\n",
+    "                    paths.push(path);\n",
+    "                    \n",
+    "                    //Show the results in div\n",
+    "                    // \"formula\" \"spacegroup_symbol\" \"code_name\" \"xc_functional\"\n",
+    "                    content = '<tr>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"formula\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"spacegroup_symbol\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"code_name\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"xc_functional\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"upload_id\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"calc_id\"] + '</td>';                    \n",
+    "                    content += '<td>' + path + '</td>';\n",
+    "                    content += '</tr>';\n",
+    "                    search_results_content.push(content);\n",
+    "                }\n",
+    "            }\n",
+    "        }\n",
+    "        search_results_content.push('</table>');\n",
+    "        document.getElementById(div_id_search_results).innerHTML = search_results_content.join('');\n",
+    "        return paths\n",
+    "    }\n",
+    "    \n",
+    "    \n",
+    "    \n",
+    "\n",
+    "    \n",
+    "    \n",
+    "    \n",
+    "    function submit_search()\n",
+    "    {\n",
+    "        \n",
+    "        var result;\n",
+    "        var formula = document.getElementById(\"keyword_chemical_formula\").value;\n",
+    "        var query_command_k_band = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_k_band_segment\";\n",
+    "        var query_command_dos =  \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_dos\";\n",
+    "        //result = getJSON(\"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\");\n",
+    "        var result_k_band = getJSON(query_command_k_band);\n",
+    "        var result_dos = getJSON(query_command_dos);\n",
+    "        var result_json_k_band = JSON.parse(result_k_band);//parse the searching results to json from URL\n",
+    "        var result_json_dos = JSON.parse(result_dos);\n",
+    "        paths_section_k_band_segment = []; \n",
+    "        paths_section_dos = [];\n",
+    "        paths_section_k_band_segment = get_paths_from_search_results(result_json_k_band, \"search_results_section_k_band_segment\", \"<br><br><font size=4em>Calculations containing band structures:</font><br>\");\n",
+    "        paths_section_dos = get_paths_from_search_results(result_json_dos, \"search_results_section_dos\", \"<br><font size=4em>Calculations containing DOS:</font><br>\");\n",
+    "     \n",
+    "        var promise = Promise.resolve();\n",
+    "        promise\n",
+    "            .then(match_band_dos())\n",
+    "            .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')))\n",
+    "            .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')));\n",
+    "        \n",
+    "        //match_band_dos();\n",
+    "              \n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')); //Read the json files, and prepare data for plot\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')); //Prepare for plot\n",
+    "    }\n",
+    "    function reset_search()\n",
+    "    {\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('search_materials'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot'));\n",
+    "    }\n",
+    "    \n",
+    "    \n",
+    "</script>\n",
+    "<font size=4em>Please input the chemical formula:</font>\n",
+    "<input type=\"text\" id=\"keyword_chemical_formula\" value=\"AlInO3\"> \n",
+    "<button class=\"button\" onclick=\"submit_search()\">Search</button>\n",
+    "<button class=\"button\" onclick=\"reset_search()\">Reset</button>\n",
+    "<br><br><br>\n",
+    "<div id=\"search_results_section_k_band_segment\"></div>\n",
+    "<div id=\"search_results_section_dos\"></div>\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {
+    "tags": [
+     "process_band_dos_data"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "    var band_obj_all = [];\n",
+       "    var dos_obj_all = [];\n",
+       "    var info_obj_all = [];\n",
+       "    //alert(\"process_band_dos_data: \" +band_paths)\n",
+       "    //alert(\"process_band_dos_data: \" +info_obj_all)\n",
+       "    function get_label_flag(coor_array)\n",
+       "    {\n",
+       "        var coor = coor_array.sort().join();\n",
+       "        if(coor == '0,0.5,0.5')\n",
+       "            return \"X\";\n",
+       "        if(coor == '0,0,0.5')\n",
+       "            return \"M\";\n",
+       "        else if(coor == '0.5,0.5,0.5')\n",
+       "            return \"L\";\n",
+       "        else if(coor == '0.375,0.375,0.75')\n",
+       "            return \"K\";\n",
+       "        else if(coor == '0.25,0.5,0.75')\n",
+       "            return \"W\";\n",
+       "        else if(coor == '0,0,0')\n",
+       "            return \"\\u0393\";\n",
+       "        else if(coor == '0.25,0.625,0.625')\n",
+       "            return \"U\";\n",
+       "        else\n",
+       "        {\n",
+       "            //alert(\"k label not found: \" + coor);\n",
+       "            return \"?\";\n",
+       "        }\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    //============Process the band structure data============\n",
+       "    function get_band_obj(band_path, dos_fermi_energy)\n",
+       "    {\n",
+       "        var band_data = JSON.parse(getJSON(band_path));\n",
+       "\n",
+       "        //---------Read section_k_band_segment------------\n",
+       "        var section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n",
+       "\n",
+       "        //--------Get the number of k band segments-------------\n",
+       "        var N_k_band_segments = section_k_band_segment.length;\n",
+       "\n",
+       "\n",
+       "        //----------Get the total number of k points in all segments---------\n",
+       "        var N_k_points_all = 0;\n",
+       "        for(var i = 0; i < N_k_band_segments; i++)\n",
+       "            N_k_points_all = N_k_points_all + section_k_band_segment[i]['band_k_points'].length;\n",
+       "\n",
+       "\n",
+       "        //--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n",
+       "        // store in k_coor_1D[N_k_points_total]-----------------\n",
+       "\n",
+       "        var band_distance_segments = [];\n",
+       "        for(i = 0; i < N_k_band_segments; i++)\n",
+       "        {\n",
+       "            var x1, x2, y1, y2, z1, z2;\n",
+       "            [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end'];  //\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n",
+       "            band_distance_segments.push(Math.pow((x1-x2), 2) + Math.pow((y1-y2), 2) + Math.pow((z1-z2), 2));\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        var band_distance_total = band_distance_segments.reduce((x,y) => x+y); //sum of band_distance_segments\n",
+       "\n",
+       "        var average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total;\n",
+       "\n",
+       "        //Prepare the parameters to rescale the k coordinates into [0,1]\n",
+       "        var step_k_point = 1.0 / N_k_points_all;\n",
+       "        var step_k_point = (1.0 + step_k_point) / N_k_points_all;\n",
+       "\n",
+       "        var k_coor_1D = [];\n",
+       "        for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points ++)\n",
+       "        {\n",
+       "            k_coor_1D.push(step_k_point * i_k_points)\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        //--------Get the eigenvalues of each band trajectory--------------\n",
+       "        /*\n",
+       "        N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n",
+       "        N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n",
+       "        band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n",
+       "        N_k_points_all = 0\n",
+       "        for i_segments in range(N_k_band_segments):\n",
+       "            band_energies = section_k_band_segment[i_segments]['band_energies']\n",
+       "            N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n",
+       "            N_k_points_per_segment = len(band_energies[0])\n",
+       "            for i_k_points in range(N_k_points_per_segment):\n",
+       "                for i_bands in range(N_bands):\n",
+       "                    band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n",
+       "                N_k_points_all = N_k_points_all + 1\n",
+       "        */\n",
+       "        //var N_k_points_per_segment = section_k_band_segment[0]['band_energies'][0].length; //suppose the numebr of k points in all the segments are the same\n",
+       "        var N_bands = section_k_band_segment[0]['band_energies'][0][0].length;\n",
+       "        var band_energies_all = new Array(N_bands);\n",
+       "        for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "            band_energies_all[i_bands] = new Array(N_k_points_all);// new Array(N_bands, N_k_points_all); //store the eigenvalues\n",
+       "\n",
+       "        var i_k_points_all = 0;\n",
+       "\n",
+       "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+       "        {\n",
+       "            var band_energies = section_k_band_segment[i_segments]['band_energies'];\n",
+       "            var N_spin_channel = band_energies.length; //Number of the spin channel --FIXME: no spin polarized\n",
+       "            var N_k_points_per_segment = band_energies[0].length;\n",
+       "            for(var i_k_points = 0; i_k_points < N_k_points_per_segment; i_k_points ++)\n",
+       "            {\n",
+       "                for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "                {\n",
+       "                    band_energies_all[i_bands][i_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * Math.pow(10, -19)) - dos_fermi_energy;\n",
+       "                }\n",
+       "                i_k_points_all = i_k_points_all + 1 ;\n",
+       "\n",
+       "            }\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "\n",
+       "        var N_labels = 0\n",
+       "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+       "        {\n",
+       "            for(var j = 0; j < 2; j++)\n",
+       "                //labels_tmp =  section_k_band_segment[i_segments]['band_segm_start_end'][j];\n",
+       "                N_labels = N_labels + 1\n",
+       "        }\n",
+       "        var label_flag = [];//[\"\" for i in range(N_labels)] //stores the flags of the labels (X, W, G, etc)\n",
+       "\n",
+       "\n",
+       "        var i_label = 0;\n",
+       "        var label_flag_last_final = \"\";\n",
+       "        var label_flag_current_initial = \"\";\n",
+       "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+       "        {\n",
+       "            var labels_coor_0 =  section_k_band_segment[i_segments]['band_segm_start_end'][0].sort();\n",
+       "            var labels_coor_1 =  section_k_band_segment[i_segments]['band_segm_start_end'][1].sort();\n",
+       "\n",
+       "            var label_flag_0 = get_label_flag(labels_coor_0);\n",
+       "            var label_flag_1 = get_label_flag(labels_coor_1);\n",
+       "\n",
+       "            var label_flag_current_initial = label_flag_0;\n",
+       "            if(label_flag_last_final == \"\")\n",
+       "                label_flag_last_final = label_flag_0;\n",
+       "\n",
+       "            if(label_flag_last_final == label_flag_current_initial)\n",
+       "                label_flag[i_label] = label_flag_current_initial;\n",
+       "            else\n",
+       "                label_flag[i_label] = label_flag_last_final + '|' + label_flag_current_initial;\n",
+       "            label_flag_last_final = label_flag_1\n",
+       "\n",
+       "\n",
+       "            i_label = i_label + 1;\n",
+       "            if(i_segments == N_k_band_segments - 1)\n",
+       "            {\n",
+       "                label_flag[i_label] = label_flag_1;\n",
+       "                i_label = i_label + 1;\n",
+       "            }\n",
+       "        }\n",
+       "        N_labels = i_label;\n",
+       "\n",
+       "        //------------Get the coordinates for the labels------------\n",
+       "        //label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n",
+       "        var label_coor_relative = [];//np.zeros((N_labels))\n",
+       "        for(i_label = 0; i_label < N_labels; i_label ++)\n",
+       "        {\n",
+       "            //Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n",
+       "            //x = labels_coor_0[0]\n",
+       "            //y = labels_coor_0[1]\n",
+       "            //z = labels_coor_0[2]\n",
+       "            //label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n",
+       "            label_coor_relative.push(step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all));\n",
+       "        }\n",
+       "        //----Store the label-----------\n",
+       "        var label_obj = [];//[['' for i in range(2)] for j in range(N_labels)]\n",
+       "        for(i_label = 0; i_label < N_labels; i_label ++)\n",
+       "        {\n",
+       "            label_obj.push([label_coor_relative[i_label], label_flag[i_label]]);\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        //-------Get VBM, CBM----------------\n",
+       "\n",
+       "        var HOMO = -1000;\n",
+       "        var LUMO = 1000;\n",
+       "        var coor_k_point_HOMO = []; //the coordinate of k point that stores HOMO\n",
+       "        var coor_k_point_LUMO = [];//np.zeros((3)) #the coordinate of k point that stores LUMO\n",
+       "        //band_gap_direct = 0.0\n",
+       "        var band_gap_indirect = 0.0;\n",
+       "\n",
+       "\n",
+       "        //band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+       "        //band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+       "        var band_energy_max = 10;\n",
+       "        var band_energy_min = -10;\n",
+       "        //N_band_energy_index = 10000\n",
+       "        //band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n",
+       "        //N_allowed_states = np.zeros(N_band_energy_index + 1)\n",
+       "        //i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n",
+       "\n",
+       "\n",
+       "        for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "        {\n",
+       "            for(var i_k_points_all = 0; i_k_points_all< N_k_points_all; i_k_points_all ++)\n",
+       "            {\n",
+       "                //i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n",
+       "                //N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n",
+       "                var band_energy = band_energies_all[i_bands][i_k_points_all];\n",
+       "                if(band_energy > 0)\n",
+       "                {\n",
+       "                    if(band_energy < LUMO)\n",
+       "                        LUMO = band_energy;\n",
+       "                }\n",
+       "                else\n",
+       "                {\n",
+       "                    if(band_energy > HOMO)\n",
+       "                        HOMO = band_energy;\n",
+       "                }\n",
+       "\n",
+       "            }\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        //#for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n",
+       "        //    if(N_allowed_states[i_band_index] > 0):\n",
+       "        //        LUMO = band_energy_min + band_energy_step * i_band_index\n",
+       "        //print('HOMO, LUMO: ',HOMO, LUMO)\n",
+       "        band_gap_indirect = Math.abs(LUMO - HOMO);\n",
+       "\n",
+       "        if(band_gap_indirect < 0.5) //VBM and CBM has to be found in another way for metals/charged system:\n",
+       "        {\n",
+       "            HOMO = -1000.0;\n",
+       "            LUMO = 1000.0;\n",
+       "            band_energy_max = 10.0;\n",
+       "            band_energy_min = 0.0;\n",
+       "            var N_band_energy_index = 10000;\n",
+       "            var band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index;\n",
+       "            var N_allowed_states = [];\n",
+       "            for(var i_state = 0; i_state < N_band_energy_index+1; i_state++)\n",
+       "                N_allowed_states.push(0);\n",
+       "\n",
+       "\n",
+       "            //get the DOS and store in N_allowed_states[]\n",
+       "            for(var i_k_points_all = 0; i_k_points_all < N_k_points_all; i_k_points_all ++)\n",
+       "            {\n",
+       "                for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "                {\n",
+       "                    var band_energy = band_energies_all[i_bands][i_k_points_all];\n",
+       "                    if((band_energy_min < band_energy)&&(band_energy < band_energy_max))\n",
+       "                    {\n",
+       "                        var i_band_index = Math.floor((band_energy - band_energy_min) / band_energy_step);\n",
+       "                        N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1;\n",
+       "                    }\n",
+       "                }\n",
+       "            }\n",
+       "\n",
+       "\n",
+       "            var if_gapped = 0;\n",
+       "            for(var i_band_index = 0; i_band_index < N_band_energy_index; i_band_index ++)//go through the energy levels from the bottom\n",
+       "            {\n",
+       "                var band_energy = band_energy_min + band_energy_step * i_band_index\n",
+       "                if(N_allowed_states[i_band_index] == 0)\n",
+       "                    if_gapped = if_gapped + 1;\n",
+       "                if((band_energy > band_energy_max - 0.5) && (if_gapped == 0))\n",
+       "                {\n",
+       "                    //alert(\"No gap found in this system. It seems to be a metal.\");\n",
+       "                    HOMO = 1000;\n",
+       "                    LUMO = 1000;\n",
+       "                    break;\n",
+       "                }\n",
+       "                //print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n",
+       "\n",
+       "                if(N_allowed_states[i_band_index] > 0)\n",
+       "                {\n",
+       "                    if(if_gapped * band_energy_step > 0.3 )//above VBM-CBM gap: LUMO\n",
+       "                    {\n",
+       "                        if(band_energy < LUMO)\n",
+       "                        {\n",
+       "                            //print(\"LUMO got!\")\n",
+       "                            LUMO = band_energy;\n",
+       "                            break; //break before touching another gap that is above the band gap\n",
+       "                        }\n",
+       "                    }\n",
+       "\n",
+       "                    if(if_gapped * band_energy_step < 0.3) //below VBM-CBM gap: HOMO\n",
+       "                    {\n",
+       "                        if(band_energy > HOMO)\n",
+       "                        {\n",
+       "                            //print(\"HOMO got!\")\n",
+       "                            HOMO = band_energy;\n",
+       "                        }\n",
+       "                    }        \n",
+       "                    if_gapped = 0;\n",
+       "                }\n",
+       "            }\n",
+       "            //alert('HOMO, LUMO for metal/charged system: '+ HOMO +\",\"+LUMO)\n",
+       "\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "\n",
+       "\n",
+       "        //Find the position of HOMO, LUMO\n",
+       "        var coor_k_point_HOMO = 0, coor_k_point_LUMO = 0;\n",
+       "        for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points++)\n",
+       "        {\n",
+       "            for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "            {\n",
+       "                if(Math.abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001)\n",
+       "                    coor_k_point_HOMO = k_coor_1D[i_k_points];\n",
+       "                if(Math.abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001)\n",
+       "                    coor_k_point_LUMO = k_coor_1D[i_k_points]; \n",
+       "            }\n",
+       "        }\n",
+       "\n",
+       "        //alert(coor_k_point_HOMO +\",\" + coor_k_point_LUMO);\n",
+       "\n",
+       "\n",
+       "        //Store the band data to band_obj\n",
+       "\n",
+       "        var band_obj = {};\n",
+       "        band_obj[\"band_x_axis\"] = k_coor_1D;\n",
+       "        band_obj[\"band_y_axis\"] = band_energies_all\n",
+       "        band_obj[\"labels\"] = label_obj;\n",
+       "        band_obj[\"HOMO_energy\"] = HOMO;\n",
+       "        band_obj[\"HOMO_coor\"] = coor_k_point_HOMO;\n",
+       "        band_obj[\"LUMO_energy\"] = LUMO;\n",
+       "        band_obj[\"LUMO_coor\"] = coor_k_point_LUMO;\n",
+       "        band_obj[\"average_N_k_points_per_inverse_distance\"] = average_N_k_points_per_inverse_distance;\n",
+       "\n",
+       "\n",
+       "        return band_obj\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    function get_dos_obj(dos_path)\n",
+       "    {\n",
+       "\n",
+       "        var dos_data = JSON.parse(getJSON(dos_path));\n",
+       "\n",
+       "        var N_dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'].length;\n",
+       "\n",
+       "        //in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n",
+       "\n",
+       "        //dos_energies = new Array(N_dos_values).fill(0.0);\n",
+       "        //dos_energies_tmp = new Array(N_dos_values).fill(0.0) #tmp array for unit convertion\n",
+       "        //dos_values = new Array(N_dos_values).fill(0.0)\n",
+       "\n",
+       "        var dos_energies = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'];\n",
+       "        var dos_values =  dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_integrated_values'];//[0]\n",
+       "\n",
+       "        //To do: check if every section_dos has 'dos_fermi_energy'\n",
+       "        var dos_fermi_energy = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_fermi_energy'];\n",
+       "        dos_fermi_energy = dos_fermi_energy  / (1.60217656535 * Math.pow(10,-19));\n",
+       "        \n",
+       "        for(var i = 0; i < N_dos_values; i++)\n",
+       "        {\n",
+       "            dos_energies[i] = dos_energies[i] / (1.60217656535 * Math.pow(10,-19)) - dos_fermi_energy;\n",
+       "        }\n",
+       "        \n",
+       "        dos_obj = {}\n",
+       "        dos_obj[\"dos_x_axis\"] = dos_energies;\n",
+       "        dos_obj[\"dos_y_axis\"] = dos_values;\n",
+       "        dos_obj[\"dos_fermi_energy\"] = dos_fermi_energy;\n",
+       "        return dos_obj\n",
+       "    }\n",
+       "    function get_info_obj(band_path)\n",
+       "    {\n",
+       "\n",
+       "        var band_data = JSON.parse(getJSON(band_path));\n",
+       "        var info_obj = {};\n",
+       "        //---------Read the information of the calculation--------\n",
+       "        info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n",
+       "        info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n",
+       "        info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+       "        info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n",
+       "\n",
+       "        //----------Get the space group information----------\n",
+       "        /*\n",
+       "        [space_group_symbol, lattice_constant] = get_space_group(band_data);\n",
+       "        info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist();\n",
+       "        info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist();\n",
+       "        */\n",
+       "\n",
+       "        return info_obj\n",
+       "    }\n",
+       "    function process_band_dos_data()\n",
+       "    {\n",
+       "        info_all = [];\n",
+       "        band_obj_all = [];\n",
+       "        dos_obj_all = [];\n",
+       "\n",
+       "        for(var i = 0; i < N_materials; i++)\n",
+       "        {\n",
+       "            var band_path = band_paths[i];\n",
+       "            var dos_path = dos_paths[i];\n",
+       "\n",
+       "\n",
+       "            var dos_obj = get_dos_obj(dos_path);\n",
+       "            var dos_fermi_energy = dos_obj[\"dos_fermi_energy\"];\n",
+       "            band_obj = get_band_obj(band_path, dos_fermi_energy);\n",
+       "            var info_obj = get_info_obj(band_path);\n",
+       "\n",
+       "            band_obj_all.push(band_obj);\n",
+       "            dos_obj_all.push(dos_obj);\n",
+       "            info_obj_all.push(info_obj);\n",
+       "        }\n",
+       "    }\n",
+       "    process_band_dos_data();\n",
+       "    //alert(\"process_band_dos_data: info_obj_all: \"+JSON.stringify(info_obj_all));\n",
+       "</script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "    var band_obj_all = [];\n",
+    "    var dos_obj_all = [];\n",
+    "    var info_obj_all = [];\n",
+    "    //alert(\"process_band_dos_data: \" +band_paths)\n",
+    "    //alert(\"process_band_dos_data: \" +info_obj_all)\n",
+    "    function get_label_flag(coor_array)\n",
+    "    {\n",
+    "        var coor = coor_array.sort().join();\n",
+    "        if(coor == '0,0.5,0.5')\n",
+    "            return \"X\";\n",
+    "        if(coor == '0,0,0.5')\n",
+    "            return \"M\";\n",
+    "        else if(coor == '0.5,0.5,0.5')\n",
+    "            return \"L\";\n",
+    "        else if(coor == '0.375,0.375,0.75')\n",
+    "            return \"K\";\n",
+    "        else if(coor == '0.25,0.5,0.75')\n",
+    "            return \"W\";\n",
+    "        else if(coor == '0,0,0')\n",
+    "            return \"\\u0393\";\n",
+    "        else if(coor == '0.25,0.625,0.625')\n",
+    "            return \"U\";\n",
+    "        else\n",
+    "        {\n",
+    "            //alert(\"k label not found: \" + coor);\n",
+    "            return \"?\";\n",
+    "        }\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    //============Process the band structure data============\n",
+    "    function get_band_obj(band_path, dos_fermi_energy)\n",
+    "    {\n",
+    "        var band_data = JSON.parse(getJSON(band_path));\n",
+    "\n",
+    "        //---------Read section_k_band_segment------------\n",
+    "        var section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n",
+    "\n",
+    "        //--------Get the number of k band segments-------------\n",
+    "        var N_k_band_segments = section_k_band_segment.length;\n",
+    "\n",
+    "\n",
+    "        //----------Get the total number of k points in all segments---------\n",
+    "        var N_k_points_all = 0;\n",
+    "        for(var i = 0; i < N_k_band_segments; i++)\n",
+    "            N_k_points_all = N_k_points_all + section_k_band_segment[i]['band_k_points'].length;\n",
+    "\n",
+    "\n",
+    "        //--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n",
+    "        // store in k_coor_1D[N_k_points_total]-----------------\n",
+    "\n",
+    "        var band_distance_segments = [];\n",
+    "        for(i = 0; i < N_k_band_segments; i++)\n",
+    "        {\n",
+    "            var x1, x2, y1, y2, z1, z2;\n",
+    "            [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end'];  //\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n",
+    "            band_distance_segments.push(Math.pow((x1-x2), 2) + Math.pow((y1-y2), 2) + Math.pow((z1-z2), 2));\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        var band_distance_total = band_distance_segments.reduce((x,y) => x+y); //sum of band_distance_segments\n",
+    "\n",
+    "        var average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total;\n",
+    "\n",
+    "        //Prepare the parameters to rescale the k coordinates into [0,1]\n",
+    "        var step_k_point = 1.0 / N_k_points_all;\n",
+    "        var step_k_point = (1.0 + step_k_point) / N_k_points_all;\n",
+    "\n",
+    "        var k_coor_1D = [];\n",
+    "        for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points ++)\n",
+    "        {\n",
+    "            k_coor_1D.push(step_k_point * i_k_points)\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        //--------Get the eigenvalues of each band trajectory--------------\n",
+    "        /*\n",
+    "        N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n",
+    "        N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n",
+    "        band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n",
+    "        N_k_points_all = 0\n",
+    "        for i_segments in range(N_k_band_segments):\n",
+    "            band_energies = section_k_band_segment[i_segments]['band_energies']\n",
+    "            N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n",
+    "            N_k_points_per_segment = len(band_energies[0])\n",
+    "            for i_k_points in range(N_k_points_per_segment):\n",
+    "                for i_bands in range(N_bands):\n",
+    "                    band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n",
+    "                N_k_points_all = N_k_points_all + 1\n",
+    "        */\n",
+    "        //var N_k_points_per_segment = section_k_band_segment[0]['band_energies'][0].length; //suppose the numebr of k points in all the segments are the same\n",
+    "        var N_bands = section_k_band_segment[0]['band_energies'][0][0].length;\n",
+    "        var band_energies_all = new Array(N_bands);\n",
+    "        for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "            band_energies_all[i_bands] = new Array(N_k_points_all);// new Array(N_bands, N_k_points_all); //store the eigenvalues\n",
+    "\n",
+    "        var i_k_points_all = 0;\n",
+    "\n",
+    "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+    "        {\n",
+    "            var band_energies = section_k_band_segment[i_segments]['band_energies'];\n",
+    "            var N_spin_channel = band_energies.length; //Number of the spin channel --FIXME: no spin polarized\n",
+    "            var N_k_points_per_segment = band_energies[0].length;\n",
+    "            for(var i_k_points = 0; i_k_points < N_k_points_per_segment; i_k_points ++)\n",
+    "            {\n",
+    "                for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "                {\n",
+    "                    band_energies_all[i_bands][i_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * Math.pow(10, -19)) - dos_fermi_energy;\n",
+    "                }\n",
+    "                i_k_points_all = i_k_points_all + 1 ;\n",
+    "\n",
+    "            }\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "\n",
+    "        var N_labels = 0\n",
+    "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+    "        {\n",
+    "            for(var j = 0; j < 2; j++)\n",
+    "                //labels_tmp =  section_k_band_segment[i_segments]['band_segm_start_end'][j];\n",
+    "                N_labels = N_labels + 1\n",
+    "        }\n",
+    "        var label_flag = [];//[\"\" for i in range(N_labels)] //stores the flags of the labels (X, W, G, etc)\n",
+    "\n",
+    "\n",
+    "        var i_label = 0;\n",
+    "        var label_flag_last_final = \"\";\n",
+    "        var label_flag_current_initial = \"\";\n",
+    "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+    "        {\n",
+    "            var labels_coor_0 =  section_k_band_segment[i_segments]['band_segm_start_end'][0].sort();\n",
+    "            var labels_coor_1 =  section_k_band_segment[i_segments]['band_segm_start_end'][1].sort();\n",
+    "\n",
+    "            var label_flag_0 = get_label_flag(labels_coor_0);\n",
+    "            var label_flag_1 = get_label_flag(labels_coor_1);\n",
+    "\n",
+    "            var label_flag_current_initial = label_flag_0;\n",
+    "            if(label_flag_last_final == \"\")\n",
+    "                label_flag_last_final = label_flag_0;\n",
+    "\n",
+    "            if(label_flag_last_final == label_flag_current_initial)\n",
+    "                label_flag[i_label] = label_flag_current_initial;\n",
+    "            else\n",
+    "                label_flag[i_label] = label_flag_last_final + '|' + label_flag_current_initial;\n",
+    "            label_flag_last_final = label_flag_1\n",
+    "\n",
+    "\n",
+    "            i_label = i_label + 1;\n",
+    "            if(i_segments == N_k_band_segments - 1)\n",
+    "            {\n",
+    "                label_flag[i_label] = label_flag_1;\n",
+    "                i_label = i_label + 1;\n",
+    "            }\n",
+    "        }\n",
+    "        N_labels = i_label;\n",
+    "\n",
+    "        //------------Get the coordinates for the labels------------\n",
+    "        //label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n",
+    "        var label_coor_relative = [];//np.zeros((N_labels))\n",
+    "        for(i_label = 0; i_label < N_labels; i_label ++)\n",
+    "        {\n",
+    "            //Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n",
+    "            //x = labels_coor_0[0]\n",
+    "            //y = labels_coor_0[1]\n",
+    "            //z = labels_coor_0[2]\n",
+    "            //label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n",
+    "            label_coor_relative.push(step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all));\n",
+    "        }\n",
+    "        //----Store the label-----------\n",
+    "        var label_obj = [];//[['' for i in range(2)] for j in range(N_labels)]\n",
+    "        for(i_label = 0; i_label < N_labels; i_label ++)\n",
+    "        {\n",
+    "            label_obj.push([label_coor_relative[i_label], label_flag[i_label]]);\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        //-------Get VBM, CBM----------------\n",
+    "\n",
+    "        var HOMO = -1000;\n",
+    "        var LUMO = 1000;\n",
+    "        var coor_k_point_HOMO = []; //the coordinate of k point that stores HOMO\n",
+    "        var coor_k_point_LUMO = [];//np.zeros((3)) #the coordinate of k point that stores LUMO\n",
+    "        //band_gap_direct = 0.0\n",
+    "        var band_gap_indirect = 0.0;\n",
+    "\n",
+    "\n",
+    "        //band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+    "        //band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+    "        var band_energy_max = 10;\n",
+    "        var band_energy_min = -10;\n",
+    "        //N_band_energy_index = 10000\n",
+    "        //band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n",
+    "        //N_allowed_states = np.zeros(N_band_energy_index + 1)\n",
+    "        //i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n",
+    "\n",
+    "\n",
+    "        for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "        {\n",
+    "            for(var i_k_points_all = 0; i_k_points_all< N_k_points_all; i_k_points_all ++)\n",
+    "            {\n",
+    "                //i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n",
+    "                //N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n",
+    "                var band_energy = band_energies_all[i_bands][i_k_points_all];\n",
+    "                if(band_energy > 0)\n",
+    "                {\n",
+    "                    if(band_energy < LUMO)\n",
+    "                        LUMO = band_energy;\n",
+    "                }\n",
+    "                else\n",
+    "                {\n",
+    "                    if(band_energy > HOMO)\n",
+    "                        HOMO = band_energy;\n",
+    "                }\n",
+    "\n",
+    "            }\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        //#for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n",
+    "        //    if(N_allowed_states[i_band_index] > 0):\n",
+    "        //        LUMO = band_energy_min + band_energy_step * i_band_index\n",
+    "        //print('HOMO, LUMO: ',HOMO, LUMO)\n",
+    "        band_gap_indirect = Math.abs(LUMO - HOMO);\n",
+    "\n",
+    "        if(band_gap_indirect < 0.5) //VBM and CBM has to be found in another way for metals/charged system:\n",
+    "        {\n",
+    "            HOMO = -1000.0;\n",
+    "            LUMO = 1000.0;\n",
+    "            band_energy_max = 10.0;\n",
+    "            band_energy_min = 0.0;\n",
+    "            var N_band_energy_index = 10000;\n",
+    "            var band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index;\n",
+    "            var N_allowed_states = [];\n",
+    "            for(var i_state = 0; i_state < N_band_energy_index+1; i_state++)\n",
+    "                N_allowed_states.push(0);\n",
+    "\n",
+    "\n",
+    "            //get the DOS and store in N_allowed_states[]\n",
+    "            for(var i_k_points_all = 0; i_k_points_all < N_k_points_all; i_k_points_all ++)\n",
+    "            {\n",
+    "                for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "                {\n",
+    "                    var band_energy = band_energies_all[i_bands][i_k_points_all];\n",
+    "                    if((band_energy_min < band_energy)&&(band_energy < band_energy_max))\n",
+    "                    {\n",
+    "                        var i_band_index = Math.floor((band_energy - band_energy_min) / band_energy_step);\n",
+    "                        N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1;\n",
+    "                    }\n",
+    "                }\n",
+    "            }\n",
+    "\n",
+    "\n",
+    "            var if_gapped = 0;\n",
+    "            for(var i_band_index = 0; i_band_index < N_band_energy_index; i_band_index ++)//go through the energy levels from the bottom\n",
+    "            {\n",
+    "                var band_energy = band_energy_min + band_energy_step * i_band_index\n",
+    "                if(N_allowed_states[i_band_index] == 0)\n",
+    "                    if_gapped = if_gapped + 1;\n",
+    "                if((band_energy > band_energy_max - 0.5) && (if_gapped == 0))\n",
+    "                {\n",
+    "                    //alert(\"No gap found in this system. It seems to be a metal.\");\n",
+    "                    HOMO = 1000;\n",
+    "                    LUMO = 1000;\n",
+    "                    break;\n",
+    "                }\n",
+    "                //print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n",
+    "\n",
+    "                if(N_allowed_states[i_band_index] > 0)\n",
+    "                {\n",
+    "                    if(if_gapped * band_energy_step > 0.3 )//above VBM-CBM gap: LUMO\n",
+    "                    {\n",
+    "                        if(band_energy < LUMO)\n",
+    "                        {\n",
+    "                            //print(\"LUMO got!\")\n",
+    "                            LUMO = band_energy;\n",
+    "                            break; //break before touching another gap that is above the band gap\n",
+    "                        }\n",
+    "                    }\n",
+    "\n",
+    "                    if(if_gapped * band_energy_step < 0.3) //below VBM-CBM gap: HOMO\n",
+    "                    {\n",
+    "                        if(band_energy > HOMO)\n",
+    "                        {\n",
+    "                            //print(\"HOMO got!\")\n",
+    "                            HOMO = band_energy;\n",
+    "                        }\n",
+    "                    }        \n",
+    "                    if_gapped = 0;\n",
+    "                }\n",
+    "            }\n",
+    "            //alert('HOMO, LUMO for metal/charged system: '+ HOMO +\",\"+LUMO)\n",
+    "\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n",
+    "        //Find the position of HOMO, LUMO\n",
+    "        var coor_k_point_HOMO = 0, coor_k_point_LUMO = 0;\n",
+    "        for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points++)\n",
+    "        {\n",
+    "            for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "            {\n",
+    "                if(Math.abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001)\n",
+    "                    coor_k_point_HOMO = k_coor_1D[i_k_points];\n",
+    "                if(Math.abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001)\n",
+    "                    coor_k_point_LUMO = k_coor_1D[i_k_points]; \n",
+    "            }\n",
+    "        }\n",
+    "\n",
+    "        //alert(coor_k_point_HOMO +\",\" + coor_k_point_LUMO);\n",
+    "\n",
+    "\n",
+    "        //Store the band data to band_obj\n",
+    "\n",
+    "        var band_obj = {};\n",
+    "        band_obj[\"band_x_axis\"] = k_coor_1D;\n",
+    "        band_obj[\"band_y_axis\"] = band_energies_all\n",
+    "        band_obj[\"labels\"] = label_obj;\n",
+    "        band_obj[\"HOMO_energy\"] = HOMO;\n",
+    "        band_obj[\"HOMO_coor\"] = coor_k_point_HOMO;\n",
+    "        band_obj[\"LUMO_energy\"] = LUMO;\n",
+    "        band_obj[\"LUMO_coor\"] = coor_k_point_LUMO;\n",
+    "        band_obj[\"average_N_k_points_per_inverse_distance\"] = average_N_k_points_per_inverse_distance;\n",
+    "\n",
+    "\n",
+    "        return band_obj\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    function get_dos_obj(dos_path)\n",
+    "    {\n",
+    "\n",
+    "        var dos_data = JSON.parse(getJSON(dos_path));\n",
+    "\n",
+    "        var N_dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'].length;\n",
+    "\n",
+    "        //in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n",
+    "\n",
+    "        //dos_energies = new Array(N_dos_values).fill(0.0);\n",
+    "        //dos_energies_tmp = new Array(N_dos_values).fill(0.0) #tmp array for unit convertion\n",
+    "        //dos_values = new Array(N_dos_values).fill(0.0)\n",
+    "\n",
+    "        var dos_energies = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'];\n",
+    "        var dos_values =  dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_integrated_values'];//[0]\n",
+    "\n",
+    "        //To do: check if every section_dos has 'dos_fermi_energy'\n",
+    "        var dos_fermi_energy = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_fermi_energy'];\n",
+    "        dos_fermi_energy = dos_fermi_energy  / (1.60217656535 * Math.pow(10,-19));\n",
+    "        \n",
+    "        for(var i = 0; i < N_dos_values; i++)\n",
+    "        {\n",
+    "            dos_energies[i] = dos_energies[i] / (1.60217656535 * Math.pow(10,-19)) - dos_fermi_energy;\n",
+    "        }\n",
+    "        \n",
+    "        dos_obj = {}\n",
+    "        dos_obj[\"dos_x_axis\"] = dos_energies;\n",
+    "        dos_obj[\"dos_y_axis\"] = dos_values;\n",
+    "        dos_obj[\"dos_fermi_energy\"] = dos_fermi_energy;\n",
+    "        return dos_obj\n",
+    "    }\n",
+    "    function get_info_obj(band_path)\n",
+    "    {\n",
+    "\n",
+    "        var band_data = JSON.parse(getJSON(band_path));\n",
+    "        var info_obj = {};\n",
+    "        //---------Read the information of the calculation--------\n",
+    "        info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n",
+    "        info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n",
+    "        info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+    "        info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n",
+    "\n",
+    "        //----------Get the space group information----------\n",
+    "        /*\n",
+    "        [space_group_symbol, lattice_constant] = get_space_group(band_data);\n",
+    "        info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist();\n",
+    "        info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist();\n",
+    "        */\n",
+    "\n",
+    "        return info_obj\n",
+    "    }\n",
+    "    function process_band_dos_data()\n",
+    "    {\n",
+    "        info_all = [];\n",
+    "        band_obj_all = [];\n",
+    "        dos_obj_all = [];\n",
+    "\n",
+    "        for(var i = 0; i < N_materials; i++)\n",
+    "        {\n",
+    "            var band_path = band_paths[i];\n",
+    "            var dos_path = dos_paths[i];\n",
+    "\n",
+    "\n",
+    "            var dos_obj = get_dos_obj(dos_path);\n",
+    "            var dos_fermi_energy = dos_obj[\"dos_fermi_energy\"];\n",
+    "            band_obj = get_band_obj(band_path, dos_fermi_energy);\n",
+    "            var info_obj = get_info_obj(band_path);\n",
+    "\n",
+    "            band_obj_all.push(band_obj);\n",
+    "            dos_obj_all.push(dos_obj);\n",
+    "            info_obj_all.push(info_obj);\n",
+    "        }\n",
+    "    }\n",
+    "    process_band_dos_data();\n",
+    "    //alert(\"process_band_dos_data: info_obj_all: \"+JSON.stringify(info_obj_all));\n",
+    "</script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 54,
+   "metadata": {
+    "scrolled": false,
+    "tags": [
+     "show_results_and_plot"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "    var N_max_show = 10; //Number of results to be shown by default\n",
+       "\n",
+       "    function show_materials_submitted_info()\n",
+       "    {\n",
+       "      //alert(\"N_materials=\" + N_materials)\n",
+       "      //\"table_materials_submitted_info\"\n",
+       "      //alert(\"show_materials_submitted_info: info_obj_all: \"+JSON.stringify(info_obj_all))\n",
+       "      var table_content = new Array(); \n",
+       "      str = '<tr>';\n",
+       "      str += '<th width=\"5%\"></th>'\n",
+       "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Atom labels</b></font></p></th>';\n",
+       "      //str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Space group</b></font></p></th>';\n",
+       "      //str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Lattice constants (in Ang)</b></font></p></th>';\n",
+       "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Program name</b></font></p></th>';\n",
+       "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Basis set type</b></font></p></th>';\n",
+       "      str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Functional</b></font></p></th>';\n",
+       "      //str += '<th width=\"20%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Number of <i>k</i> points per inverse distance</b></font></p></th>';\n",
+       "      str += '</tr>'; //first row: head\n",
+       "      table_content.push(str);\n",
+       "\n",
+       "      for(var i = 0; i < N_materials; i++) //add info of each material\n",
+       "      {\n",
+       "        //alert(\"show_materials_submitted_info: material \"+ i);  \n",
+       "        table_content.push('<tr>');\n",
+       "\n",
+       "        table_content.push('<td>');    \n",
+       "        str = '<input type = \\\"checkbox\\\" name = \"checkbox_material\" id = \\\"checkbox_material' + i.toString() + '\\\" unchecked  onclick=\\\"checkbox_material(this.id)\\\">';\n",
+       "        str += \"<b>&nbsp&nbsp#\" + (i+1).toString() + \"</b>\";\n",
+       "        table_content.push(str);\n",
+       "        table_content.push('</td>');\n",
+       "\n",
+       "        table_content.push('<td>');    \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"atom_labels\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got atom_labels\");\n",
+       "\n",
+       "        /*\n",
+       "        table_content.push('<td>');    \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"space_group_symbol\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got space_group_symbol\");\n",
+       "\n",
+       "        table_content.push('<td>');    \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"lattice_constant\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got lattice_constant\");\n",
+       "        */\n",
+       "          \n",
+       "        table_content.push('<td>'); \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"program_name\"].toUpperCase() + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got program_name\");\n",
+       "\n",
+       "        table_content.push('<td>'); \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"program_basis_set_type\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got program_basis_set_type\");\n",
+       "\n",
+       "\n",
+       "        table_content.push('<td>'); \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"XC_functional_name\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got XC_functional_name\");\n",
+       "\n",
+       "        /*\n",
+       "        table_content.push('<td>'); \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got average_N_k_points_per_inverse_distance\");\n",
+       "        */\n",
+       "        table_content.push('</tr>');\n",
+       "\n",
+       "      }\n",
+       "      \n",
+       "      document.getElementById(\"table_materials_submitted_info\").innerHTML = table_content.join('');\n",
+       "    }\n",
+       "\n",
+       "    function clean_materials_selection()\n",
+       "    {\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_material\");\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "      {\n",
+       "        //choices_compare[i].removeAttribute('checked');\n",
+       "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+       "        choices_compare[i].checked = \"\";\n",
+       "      }\n",
+       "    }\n",
+       "\n",
+       "    function select_all()\n",
+       "    {\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_material\");\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "      {\n",
+       "        //choices_compare[i].removeAttribute('checked');\n",
+       "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+       "        choices_compare[i].checked = \"checked\";\n",
+       "      }\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "\n",
+       "    function process()\n",
+       "    {\n",
+       "        //alert(\"Process:\"+band_paths)\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_js_plot'));\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_materials_submitted_info'));\n",
+       "        show_materials_submitted_info();\n",
+       "        document.getElementById(\"table_visualize\").innerHTML = \"\";\n",
+       "        str = N_materials.toString();\n",
+       "        document.getElementById(\"n_materials\").innerHTML = \"Number of materials submitted: \" + str + \"<font size = 1px color = #C0C0C0  > &nbsp Please press \\'Visualize\\' to visualize the band structure. </font>\";\n",
+       "        document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n",
+       "    }\n",
+       "        \n",
+       "\n",
+       "    var image_band = '';\n",
+       "    var image_dos = '';\n",
+       "    var image_band_links = new Array(N_materials); //store the URL of each band figure -> used to compare 2 figures\n",
+       "    var image_band_links_selected = [];\n",
+       "    var image_band_selected_Number = []; //record which i_material has been selected\n",
+       "\n",
+       "\n",
+       "\n",
+       "    function prepare(N_materials_show)\n",
+       "    {\n",
+       "      document.getElementById(\"table_visualize\").innerHTML = \"\";\n",
+       "      var table_content = new Array(); \n",
+       "      //document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n",
+       "      //-----Generate the html tables for each material--------\n",
+       "      for(var i = 0; i < N_materials_show; i++)\n",
+       "      {\n",
+       "        checkbox_material_id = \"checkbox_material\" + i.toString();\n",
+       "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+       "        if(if_selected != 1)\n",
+       "        {\n",
+       "          continue;\n",
+       "        }\n",
+       "\n",
+       "        table_content.push('<tr>');\n",
+       "        div_string = '<div style = \\\"height: 20px\\\"></div>';\n",
+       "        table_content.push(div_string);\n",
+       "        table_content.push('<th>');\n",
+       "\n",
+       "        //add main container div\n",
+       "        div_string = '<div id = \\\"div_band_dos' + i.toString() + '\\\" class = \\\"div_band_dos\\\" >';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //show No. of the material\n",
+       "        i_material = i + 1;\n",
+       "        div_string = '<div style = \\\"height:30px\\; font-size: 15pt;\">' + '#' + i_material.toString() + '</div>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //show band_path/dos info\n",
+       "        div_string = '<div style = \\\"height:30px\\\">' + 'Band: &nbsp&nbsp' + band_paths[i] + ',&nbsp&nbsp&nbsp&nbspDOS: &nbsp&nbsp' + dos_paths[i] + '</div>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add div_band\n",
+       "        div_string = '<div id = \\\"div_band' + i.toString() + '\\\" class = \\\"div_band\\\" ></div>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add div_dos\n",
+       "        div_string = '<div id = \\\"div_dos' + i.toString() + '\\\" class = \\\"div_dos\\\" ></div>';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add div_tools\n",
+       "        div_string = '<div id = \\\"div_tools' + i.toString() + '\\\" class = \\\"div_tools\\\" >';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add: infomation\n",
+       "        div_string = '<div id = \\\"div_info' + i.toString() + '\\\">atom_labels<br>program_name</div>';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add: custom scale\n",
+       "        div_string = '<br><p style=\\\"color: #000;font-weight: 100; font-size: 10pt; align:left\\\"> Set the lower and upper limit of energy scale (in eV): <br><br><font color=\\\"black\\\" size = 3px> Lower limit: &nbsp&nbsp </font><textarea  id=\\\"lowerlimit' + i.toString() + '\\\"  rows=\\\"1\\\" style = \\\"width: 70px;\\\">-10</textarea> <font color=\\\"black\\\" size = 3px> &nbsp eV</font> &nbsp&nbsp&nbsp<font color=\\\"black\\\" size = 3px> Upper limit: &nbsp&nbsp </font><textarea  id=\\\"upperlimit' + i.toString() + '\\\"  rows=\\\"1\\\" style = \\\"width: 70px;\\\">10</textarea> <font color=\\\"black\\\" size = 3px> &nbsp eV&nbsp&nbsp&nbsp</font></p>';\n",
+       "        table_content.push(div_string);\n",
+       "        div_string = '<br><button class = \\\"button_tools\\\" id = \\\"button_customscale' + i.toString() + '\\\"  onclick = \\\"customscale(this.id)\\\"> Rescale </button>';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "\n",
+       "        //add button:autoscale\n",
+       "        div_string = '<button class = \\\"button_tools\\\" id = \\\"button_autoscale' + i.toString() + '\\\"  onclick = \\\"autoscale(this.id)\\\" title = \\\"(-10 eV, 10 eV)\\\"> Autoscale </button>';    \n",
+       "        table_content.push(div_string);\n",
+       "        //add button:fullscale\n",
+       "        div_string = '<button class = \\\"button_tools\\\" id = \\\"button_fullscale' + i.toString() + '\\\"  onclick = \\\"fullscale(this.id)\\\" title = \\\"(-100 eV, 100 eV)\\\"> Full scale </button><br><br>';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //table_content.push(\"Select and zoom:\");\n",
+       "\n",
+       "        /*//overview for select and zoom\n",
+       "        div_string = '<div id = \\\"div_overview' + i.toString() + '\\\" class = \\\"div_overview\\\" ></div>';    //  <div id=\"overview\" style=\"width:300px;height:200px; margin-left:10px; margin-top: 50px; padding-top: 0px\"></div>\n",
+       "        table_content.push(div_string);\n",
+       "        div_string = '<p id = \\\"overviewLegend' + i.toString() + '\\\"  ></p>';    //  <p id=\"overviewLegend\" style=\"margin-left:10px\"></p>\n",
+       "        table_content.push(div_string);*/\n",
+       "\n",
+       "        //download figures as png\n",
+       "        div_string = '<a id = \\\"img_band' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download band </a>';\n",
+       "        table_content.push(div_string);    \n",
+       "        div_string = '<a id = \\\"img_dos' + i.toString() + '\\\" class = \\\"button_tools\\\"  target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download DOS </a>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add show VBM & CBM\n",
+       "        div_string = '<br><br><p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_VBM' + i.toString() + '\\\" unchecked  onclick=\\\"show_VBM(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Show VBM </font>  (<font color=\\\"blue\\\">\\•</font>) <font color=\\\"black\\\" size = 3px> and CBM </font>(<font color=\\\"red\\\">\\•</font>) </p>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "\n",
+       "        table_content.push('</div>');//div_tools\n",
+       "\n",
+       "        //checkbox for comparison\n",
+       "        div_string = '<div id = \\\"div_checkbox_compare' + i.toString() + '\\\" class = \\\"div_checkbox_compare\\\" >';\n",
+       "        table_content.push(div_string);\n",
+       "        //div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n",
+       "        div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" checked = \\\"unchecked\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n",
+       "        table_content.push(div_string);\n",
+       "        table_content.push('</div>');//div_checkbox_compare\n",
+       "\n",
+       "\n",
+       "        table_content.push('</div>');//div_band_dos\n",
+       "        table_content.push('</th>');\n",
+       "        table_content.push('</tr>'); \n",
+       "      }\n",
+       "\n",
+       "      document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    function visualize_band_dos()\n",
+       "    {\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_jquery'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_axislabels'));\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_dashes'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_navigate'));\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_selection'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_flot_legendoncanvas'));\n",
+       "        document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n",
+       "        document.getElementById(\"div_compare_buttons\").style.visibility=\"\";\n",
+       "\n",
+       "\n",
+       "\n",
+       "        if(N_materials > N_max_show)\n",
+       "        {\n",
+       "            document.getElementById(\"div_showall\").style.visibility=\"visible\";\n",
+       "            document.getElementById(\"checkbox_showall\").checked = \"\";\n",
+       "        }              \n",
+       "\n",
+       "        N_materials_show = Math.min(N_max_show, N_materials);\n",
+       "\n",
+       "        prepare(N_materials_show);\n",
+       "        clean_compare_list();\n",
+       "        plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    function show_all(id)//\"plot_placeholder\"\n",
+       "    {\n",
+       "        var if_showall=0;\n",
+       "        if_showall = check_show_VBM(id);\n",
+       "        if(if_showall == 1)\n",
+       "        {\n",
+       "            N_materials_show = N_materials;\n",
+       "            prepare(N_materials_show);\n",
+       "            clean_compare_list();\n",
+       "            plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+       "        }\n",
+       "        else\n",
+       "        {\n",
+       "            N_materials_show = Math.min(N_max_show, N_materials);\n",
+       "            prepare(N_materials_show);\n",
+       "            clean_compare_list();\n",
+       "            plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+       "        }\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    \n",
+       "    //------------------Tool used to get the content from textarea---------------------\n",
+       "    function get_text(textarea_id)\n",
+       "    {\n",
+       "      var text = document.getElementById(textarea_id).value;\n",
+       "      return text;\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "\n",
+       "    //-------------------Compare 2 band figures----------------------------------------\n",
+       "\n",
+       "\n",
+       "    function check_compare(id)//checkbox_compare' + i.toString() + '\\\" unchecked  onclick=\\\"check_compare(this.id)\n",
+       "    {\n",
+       "      var x = document.getElementById(id);\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+       "      var N_chosen = 0;\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "      {\n",
+       "        if(choices_compare[i].checked)\n",
+       "        {\n",
+       "          N_chosen ++;\n",
+       "        }\n",
+       "      }\n",
+       "      if(N_chosen == 2) // In max. only 2 figures could be selected and compared.\n",
+       "      {\n",
+       "        for(var i=0; i<choices_compare.length; i++)\n",
+       "        {\n",
+       "          if(!choices_compare[i].checked)\n",
+       "          {\n",
+       "            choices_compare[i].disabled = 'disabled';\n",
+       "          }\n",
+       "        }\n",
+       "      }\n",
+       "      else\n",
+       "      {\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "        {\n",
+       "          choices_compare[i].removeAttribute('disabled');\n",
+       "        }\n",
+       "      }\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    function compare()\n",
+       "    {\n",
+       "        $(\"#div_compare\").fadeIn(600);//show div for comparison\n",
+       "        //check_compare(-100);\n",
+       "\n",
+       "        var compare_list = [];\n",
+       "        compare_list = make_compare_list();\n",
+       "                //[i_material_1, i_material_2] = make_compare_list();\n",
+       "        i_material_1 = compare_list[0];\n",
+       "        i_material_2 = compare_list[1];\n",
+       "        //document.getElementById(\"demo\").innerHTML = \"In add info compare:\" + i_material_1.toString() + i_material_2.toString();\n",
+       "        compare_figures(i_material_1, i_material_2);  \n",
+       "    }\n",
+       "    function make_compare_list()\n",
+       "    {\n",
+       "      //get the links to the images\n",
+       "      images_selected_links = []; //store the links to the figures for comparison\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+       "      var N_chosen = 0;\n",
+       "      var str = ''; //tmp str for debug\n",
+       "      var figure_selected = new Array(2);\n",
+       "      for(var i=0; i<choices_compare.length; i++) //check which figures are selected\n",
+       "      {\n",
+       "        if(choices_compare[i].checked)\n",
+       "        {\n",
+       "          id_chosen = choices_compare[i].id;\n",
+       "          i_chosen = Math.round(id_chosen.substring(16));\n",
+       "          var tmp_str = image_band_links[i_chosen];\n",
+       "          images_selected_links.push(tmp_str);\n",
+       "          figure_selected[N_chosen] = i_chosen;\n",
+       "          N_chosen ++;\n",
+       "          //str += beakerx.image_band_links[i];\n",
+       "        }\n",
+       "      }\n",
+       "      var i_material_1 = 0;\n",
+       "      var i_material_2 = 0;\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'In making comare list';\n",
+       "      image_band_links_selected = images_selected_links;\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'In making comare list: next';\n",
+       "      if(N_chosen == 2)\n",
+       "      {\n",
+       "        i_material_1 = figure_selected[0];\n",
+       "        i_material_2 = figure_selected[1];\n",
+       "      }\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'Compare_list: ' +i_material_1.toString() + ' ' + i_material_2.toString();\n",
+       "\n",
+       "      return [i_material_1, i_material_2];\n",
+       "    }\n",
+       "\n",
+       "    function check_compare_scale(i_material_1, i_material_2)\n",
+       "    {\n",
+       "      lowerlimit_id_1 = \"lowerlimit\" + i_material_1.toString();\n",
+       "      lowerlimit_id_2 = \"lowerlimit\" + i_material_2.toString();\n",
+       "      upperlimit_id_1 = \"upperlimit\" + i_material_1.toString();\n",
+       "      upperlimit_id_2 = \"upperlimit\" + i_material_2.toString();\n",
+       "\n",
+       "      lowerlimit_1 = parseFloat(document.getElementById(lowerlimit_id_1).innerHTML);\n",
+       "      lowerlimit_2 = parseFloat(document.getElementById(lowerlimit_id_2).innerHTML);\n",
+       "      upperlimit_1 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n",
+       "      upperlimit_2 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n",
+       "      if((lowerlimit_1 != lowerlimit_2) || (upperlimit_1 != upperlimit_2))\n",
+       "        return -1;\n",
+       "      else\n",
+       "        return 1;\n",
+       "    }\n",
+       "\n",
+       "    function compare_figures(i_material_1, i_material_2)\n",
+       "    {\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_query_beforeafter'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_compare_slide'));\n",
+       "        add_info_compare(i_material_1, i_material_2);\n",
+       "        document.getElementById(\"div_compare_container\").scrollIntoView({ behavior: 'smooth' }); \n",
+       "        document.getElementById(\"div_compare_container\").scrollTop += 50;\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    function clean_compare_list()\n",
+       "    {\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "      {\n",
+       "        //choices_compare[i].removeAttribute('checked');\n",
+       "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+       "        choices_compare[i].checked = \"\";\n",
+       "        choices_compare[i].removeAttribute('disabled');\n",
+       "      }\n",
+       "    }\n",
+       "\n",
+       "    //-----------Add information about the calculation to \"div_tools\"---------------\n",
+       "    function add_info(i)\n",
+       "    {\n",
+       "      \n",
+       "      //document.getElementById(\"demoa\").innerHTML = i.toString() + div_info_id;\n",
+       "      //for(var i = 0; i < beakerx.N_materials; i++)\n",
+       "      //{\n",
+       "      div_info_id = \"div_info\" + i.toString();\n",
+       "\n",
+       "      var str = '';\n",
+       "      str += \"<br> <p style=\\\"text-align:left\\\"><font size = 3pt><b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"atom_labels\"] + '</font></p>';\n",
+       "      //str += \"<font size = 3pt><b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"space_group_symbol\"] + '</font>';\n",
+       "      //str += \"<font size = 3pt><b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"lattice_constant\"] + '</font>';\n",
+       "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_name\"].toUpperCase() + '</font></p>';\n",
+       "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_basis_set_type\"] + '</font></p>';\n",
+       "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"XC_functional_name\"] + '</font></p>';\n",
+       "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3) + '</font></p>';\n",
+       "      document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n",
+       "      //document.getElementById('program_name_1').innerHTML = \"<b>Code:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"program_name\"];\n",
+       "      //document.getElementById('program_basis_set_type_1').innerHTML = \"<b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"program_basis_set_type\"];\n",
+       "      //document.getElementById('XC_functional_name_1').innerHTML = \"<b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"XC_functional_name\"];  \n",
+       "      //}\n",
+       "      \n",
+       "    }\n",
+       "    function add_info_compare(i,j)\n",
+       "    {\n",
+       "\n",
+       "      div_info_id = \"div_compare_info\";\n",
+       "      var str = '';\n",
+       "\n",
+       "      if_same_scale = check_compare_scale(i_material_1, i_material_2);\n",
+       "      if(if_same_scale == -1)\n",
+       "      {\n",
+       "        str = '<b><font size = \"15pt\" color=\"#940000\">Error: Different lower/upper limits.</font></b><br>';\n",
+       "        document.getElementById(\"div_compare_container\").innerHTML = str;\n",
+       "        document.getElementById(div_info_id).innerHTML = '';\n",
+       "        return;\n",
+       "      }\n",
+       "\n",
+       "      str += \"<br><b><font-size:15pt>Information of the first calculation (left):</font></b> <br>\";\n",
+       "      str += \"<br> <b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"atom_labels\"];\n",
+       "      //str += \"<br> <b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"space_group_symbol\"];\n",
+       "      //str += \"<br> <b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"lattice_constant\"];\n",
+       "      str += \"<br> <b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_name\"].toUpperCase();\n",
+       "      str += \"<br> <b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_basis_set_type\"];\n",
+       "      str += \"<br> <b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"XC_functional_name\"];\n",
+       "      str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+       "      str += \"<br><br><br><b><font-size:15pt>Information of the second calculation (right):</font></b><br>\";\n",
+       "      str += \"<br> <b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"atom_labels\"];\n",
+       "      //str += \"<br> <b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"space_group_symbol\"];\n",
+       "      //str += \"<br> <b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"lattice_constant\"];\n",
+       "      str += \"<br> <b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"program_name\"].toUpperCase();\n",
+       "      str += \"<br> <b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"program_basis_set_type\"];  \n",
+       "      str += \"<br> <b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"XC_functional_name\"];\n",
+       "      str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+       "      document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "\n",
+       "    //-----------------------Show/hide VBM, CBM-------------------------\n",
+       "    function check_show_VBM(checkbox_VBM_id)\n",
+       "    {\n",
+       "      var x = document.getElementById(checkbox_VBM_id);\n",
+       "      var if_checked = 0;\n",
+       "      if(x.checked)//== \"checked\")\n",
+       "      {\n",
+       "        //document.getElementById(\"demoa\").innerHTML = \"checked!\";\n",
+       "        if_checked = 1;\n",
+       "      }\n",
+       "      else if (x.unchecked)// == \"unchecked\")\n",
+       "      {\n",
+       "        //document.getElementById(\"demoa\").innerHTML = \"unchecked!\";\n",
+       "        if_checked = -1;\n",
+       "      }\n",
+       "      else\n",
+       "      {\n",
+       "        //document.getElementById(\"demoa\").innerHTML = \"nothing detected!\";\n",
+       "      }\n",
+       "      return if_checked;\n",
+       "    }\n",
+       "\n",
+       "    function check_if_in_compare_list(i) // check if the current material i is to be compared\n",
+       "    {\n",
+       "\n",
+       "      var checkbox_compare_id = \"checkbox_compare\" + i.toString();\n",
+       "      var if_compare = check_show_VBM(checkbox_compare_id);\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'if_compare of ' + i.toString() + ' : ' + if_compare.toString();\n",
+       "      var i_compare_material_1, i_compare_material_2;\n",
+       "      [i_compare_material_1, i_compare_material_2] = make_compare_list();\n",
+       "      var i_in_compare_list = -1;\n",
+       "      if(i_compare_material_1 == i)\n",
+       "      {\n",
+       "        i_in_compare_list = 1;\n",
+       "      }\n",
+       "      else if (i_compare_material_2 == i)\n",
+       "      {\n",
+       "        i_in_compare_list = 2;\n",
+       "      }\n",
+       "      else\n",
+       "      {\n",
+       "        i_in_compare_list = 0;\n",
+       "      }\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'Checking ' + i.toString() + ' in Compare_list:  ' + i_in_compare_list.toString();\n",
+       "      return [if_compare, i_in_compare_list];\n",
+       "    }\n",
+       "\n",
+       "    function show_VBM(id)\n",
+       "    {\n",
+       "      //prepare(\"new\");\n",
+       "      //var if_show_VBM = -1;\n",
+       "      var len_id = id.length;\n",
+       "      var i_material = id.substring(12);\n",
+       "      var i = Math.round(i_material);\n",
+       "\n",
+       "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "\n",
+       "      var if_compare, i_in_compare_list;\n",
+       "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+       "      //document.getElementById(\"demo\").innerHTML = i.toString() + ' in Compare_list:  ' + i_in_compare_list.toString();\n",
+       "\n",
+       "      plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    //---------------------Functions to rescale-------------------------------------------\n",
+       "    function autoscale(id)\n",
+       "    {\n",
+       "      var len_id = id.length;\n",
+       "      var i_material = id.substring(16);\n",
+       "      var i = Math.round(i_material);\n",
+       "\n",
+       "      upperlim_id = \"upperlimit\" + i_material;\n",
+       "      document.getElementById(upperlim_id).innerHTML =\"10.0\";\n",
+       "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+       "      document.getElementById(lowerlim_id).innerHTML =\"-10.0\";\n",
+       "\n",
+       "\n",
+       "      //document.getElementById(\"demoa\").innerHTML =i_material;\n",
+       "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "\n",
+       "      var if_compare, i_in_compare_list;\n",
+       "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+       "\n",
+       "\n",
+       "      plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    function fullscale(id)\n",
+       "    {\n",
+       "      var len_id = id.length;\n",
+       "      var i_material = id.substring(16);\n",
+       "      var i = Math.round(i_material);\n",
+       "\n",
+       "      upperlim_id = \"upperlimit\" + i_material;\n",
+       "      document.getElementById(upperlim_id).innerHTML =\"100.0\";\n",
+       "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+       "      document.getElementById(lowerlim_id).innerHTML =\"-100.0\";\n",
+       "\n",
+       "      //document.getElementById(\"demoa\").innerHTML =i_material;\n",
+       "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "\n",
+       "      var if_compare, i_in_compare_list;\n",
+       "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+       "\n",
+       "\n",
+       "\n",
+       "      plot_band_dos_i(i, -100, 100, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    function customscale(id)\n",
+       "    {\n",
+       "      var len_id = id.length;\n",
+       "      var i_material = id.substring(18);\n",
+       "      var i = Math.round(i_material);\n",
+       "      //\n",
+       "      upperlim_id = \"upperlimit\" + i_material;\n",
+       "      upperlim = document.getElementById(upperlim_id).value;\n",
+       "      upperlim_float = Math.round(upperlim);\n",
+       "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+       "      lowerlim = document.getElementById(lowerlim_id).value;\n",
+       "      lowerlim_float = Math.round(lowerlim);\n",
+       "\n",
+       "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "\n",
+       "      var if_compare, i_in_compare_list;\n",
+       "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+       "\n",
+       "\n",
+       "\n",
+       "      plot_band_dos_i(i, lowerlim_float, upperlim_float, if_show_VBM, if_compare, i_in_compare_list);  \n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    function plot_band_dos(lowerLim, upperLim, N_materials_show)\n",
+       "    {\n",
+       "      placeholder_band = \"#div_band1\";\n",
+       "      placeholder_dos = \"#div_dos1\";\n",
+       "     // lowerLim = -10.01\n",
+       "      //upperLim = 10.01\n",
+       "\n",
+       "\n",
+       "\n",
+       "      //alert(\"plot_band_dos\");\n",
+       "      //prepare();\n",
+       "      for(var i = 0; i < N_materials_show; i++)\n",
+       "      {\n",
+       "        \n",
+       "        var checkbox_material_id = \"checkbox_material\" + i.toString();\n",
+       "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+       "        if(if_selected != 1)\n",
+       "        {\n",
+       "          continue;\n",
+       "        }\n",
+       "        add_info(i);\n",
+       "      }\n",
+       "\n",
+       "      //------Plot----------------\n",
+       "        /*\n",
+       "      for(var i_material = 0; i_material < N_materials_show; i_material++)\n",
+       "      {\n",
+       "\n",
+       "        //alert(\"Material \"+i);\n",
+       "        var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n",
+       "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+       "        if(if_selected != 1)\n",
+       "        {\n",
+       "          continue;\n",
+       "        }\n",
+       "\n",
+       "        plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n",
+       "      }\n",
+       "        */\n",
+       "      //alert(\"next:for\")\n",
+       "      for (let i_material = 0, p = Promise.resolve(); i_material < N_materials_show; i_material++) {\n",
+       "        p = p.then(_ => new Promise(resolve =>\n",
+       "            setTimeout(function () {\n",
+       "                //alert(i_material)\n",
+       "                var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n",
+       "                var if_selected = check_show_VBM(checkbox_material_id);\n",
+       "                if(if_selected == 1)\n",
+       "                {\n",
+       "                    plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n",
+       "                }\n",
+       "                resolve();\n",
+       "            }, 0)\n",
+       "        ));\n",
+       "      }\n",
+       "\n",
+       "\n",
+       "      return 1;\n",
+       "    }\n",
+       "\n",
+       "    var i = 0\n",
+       "    var lowerLim = -10\n",
+       "    var upperLim = 10\n",
+       "    var if_show_VBM = 0\n",
+       "    var if_compare = 0\n",
+       "    var i_in_compare_list = -1\n",
+       "\n",
+       "\n",
+       "    \n",
+       "    function plot_band_dos_i(i_material, lowerLim_material, upperLim_material, if_show_VBM_material, if_compare_material, i_in_compare_list_material)\n",
+       "    {\n",
+       "        //alert(\"plot_band_dos_i\")\n",
+       "\n",
+       "        i = i_material;\n",
+       "        lowerLim = lowerLim_material;\n",
+       "        upperLim = upperLim_material;\n",
+       "        if_show_VBM = if_show_VBM_material;\n",
+       "        if_compare = if_compare_material;\n",
+       "        i_in_compare_list = i_in_compare_list_material;\n",
+       "        //alert(\"plot_band_dos_i: i_material: \"+i)\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_band'));\n",
+       "        //alert('i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list')\n",
+       "        //plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_dos'));\n",
+       "    }    \n",
+       "</script>\n",
+       "\n",
+       "                                \n",
+       "                                \n",
+       "<br><br>\n",
+       "<button  class=\"button\" onclick=\"process()\">Process data</button>\n",
+       "<br><br>\n",
+       "<div id = \"n_materials\" style = \"font-size: 18px; font-weight: 100; height: 60px; width: 100%;\"> Number of materials submitted: 0</div>\n",
+       "<div id = \"show_materials_submitted\" style = \"font-size: 20px; font-color: black;\"> </div>\n",
+       "\n",
+       "<div style = \"width :100%; height: 30px;\"></div> \n",
+       "<p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select materials to visualize the band structure and DOS:</p>\n",
+       "<div style = \"width :100%; height: 10px;\"></div> \n",
+       "<button class = \"button\" onclick = \"clean_materials_selection()\"> Clean selections </button> \n",
+       "<button class = \"button\" onclick = \"select_all()\"> Select all </button> \n",
+       "<button class = \"button\" onclick = \"visualize_band_dos()\"> Visualize </button> \n",
+       "<div style = \"width :100%; height: 30px;\"></div> \n",
+       "\n",
+       "<div id = \"show_materials_submitted_info\" style = \"width: 100%; font-size: 20px; font-color: black;\"> \n",
+       "  <table id = \"table_materials_submitted_info\" style=\"width:100%\"> </table>\n",
+       "</div>\n",
+       "\n",
+       "<div style = \"width :100%; height: 30px;\"></div> \n",
+       "\n",
+       "\n",
+       "\n",
+       "\n",
+       "<div id=\"div_compare_buttons\" style=\"visibility:hidden\">\n",
+       "  <br><br><br>\n",
+       "  <p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select two materials in the checkbox on the right for comparison:</p>\n",
+       "  <p style=\"color: #000;font-weight: 1000; font-size: 8pt;\"></p>\n",
+       "  <button class = \"button\" onclick = \"clean_compare_list()\"> Clean selections </button> \n",
+       "  <button class = \"button\" onclick = \"compare();compare()\" title = \"Select 2 materials in the checkbox below and compare: please make sure that the upper/lower limits are the same (using Rescale/Autoscale buttons).\" > Compare</button>\n",
+       "</div>\n",
+       "\n",
+       "\n",
+       "\n",
+       "<div id = \"div_showall\" style = \"width: 100%; visibility:hidden\">\n",
+       "  <div style = \"width: 100%; height: 30px; \"></div>\n",
+       "  <input type = \"checkbox\" id = \"checkbox_showall\" unchecked onclick=\"show_all(this.id)\"/> <font color=\"black\" size = 3px> Show all results </font><font size = 2px color = \"#666\"> (By default only the first 10 results are shown.) </font> \n",
+       "  <div style = \"width: 100%; height: 30px; \"></div>\n",
+       "</div>\n",
+       "\n",
+       "\n",
+       "\n",
+       "\n",
+       "\n",
+       "<div id = \"div_compare\" style = \"position: fixed; top: 20%; left: 10%; width: 1200px; height: 600px; z-index: 999999; border: 1px solid #555; background-color: #fff; display: none\" onclick = \"$(this).fadeOut(500)\"> \n",
+       "  \n",
+       "  <div style = \"float: right; width: 80px; height: 25px; margin-top: 10px; margin-right: 10px; z-index: 1000000; border: 1px solid #555; text-align: center; vertical-align: middle; background-color: #f9f9f9; font-size:12pt; font-color: #000; cursor:pointer;\" > CLOSE </div> <!--button to close the div-->\n",
+       "  <div id = \"div_compare_info\" style = \" width: 350px; height: 500px; float: right; margin-top: 50px; margin-right: 10px; z-index: 10000000;\"></div>\n",
+       "  <div id = \"div_compare_container\" style = \"margin-top: 50px; margin-left: 100px; width: 600px; height: 300px;\">\n",
+       "    <div class=\"g-before-after\" id = \"div_compare_containerx\"></div>\n",
+       "  </div>\n",
+       "</div>\n",
+       "\n",
+       "\n",
+       "<div id = \"demo\"></div>\n",
+       "\n",
+       "<div id = \"plot_placeholder\">\n",
+       "    <div><br></div>\n",
+       "    <table id = \"table_visualize\"> </table>\n",
+       "</div>\n",
+       "<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "    var N_max_show = 10; //Number of results to be shown by default\n",
+    "\n",
+    "    function show_materials_submitted_info()\n",
+    "    {\n",
+    "      //alert(\"N_materials=\" + N_materials)\n",
+    "      //\"table_materials_submitted_info\"\n",
+    "      //alert(\"show_materials_submitted_info: info_obj_all: \"+JSON.stringify(info_obj_all))\n",
+    "      var table_content = new Array(); \n",
+    "      str = '<tr>';\n",
+    "      str += '<th width=\"5%\"></th>'\n",
+    "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Atom labels</b></font></p></th>';\n",
+    "      //str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Space group</b></font></p></th>';\n",
+    "      //str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Lattice constants (in Ang)</b></font></p></th>';\n",
+    "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Program name</b></font></p></th>';\n",
+    "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Basis set type</b></font></p></th>';\n",
+    "      str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Functional</b></font></p></th>';\n",
+    "      //str += '<th width=\"20%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Number of <i>k</i> points per inverse distance</b></font></p></th>';\n",
+    "      str += '</tr>'; //first row: head\n",
+    "      table_content.push(str);\n",
+    "\n",
+    "      for(var i = 0; i < N_materials; i++) //add info of each material\n",
+    "      {\n",
+    "        //alert(\"show_materials_submitted_info: material \"+ i);  \n",
+    "        table_content.push('<tr>');\n",
+    "\n",
+    "        table_content.push('<td>');    \n",
+    "        str = '<input type = \\\"checkbox\\\" name = \"checkbox_material\" id = \\\"checkbox_material' + i.toString() + '\\\" unchecked  onclick=\\\"checkbox_material(this.id)\\\">';\n",
+    "        str += \"<b>&nbsp&nbsp#\" + (i+1).toString() + \"</b>\";\n",
+    "        table_content.push(str);\n",
+    "        table_content.push('</td>');\n",
+    "\n",
+    "        table_content.push('<td>');    \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"atom_labels\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got atom_labels\");\n",
+    "\n",
+    "        /*\n",
+    "        table_content.push('<td>');    \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"space_group_symbol\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got space_group_symbol\");\n",
+    "\n",
+    "        table_content.push('<td>');    \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"lattice_constant\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got lattice_constant\");\n",
+    "        */\n",
+    "          \n",
+    "        table_content.push('<td>'); \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"program_name\"].toUpperCase() + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got program_name\");\n",
+    "\n",
+    "        table_content.push('<td>'); \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"program_basis_set_type\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got program_basis_set_type\");\n",
+    "\n",
+    "\n",
+    "        table_content.push('<td>'); \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"XC_functional_name\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got XC_functional_name\");\n",
+    "\n",
+    "        /*\n",
+    "        table_content.push('<td>'); \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got average_N_k_points_per_inverse_distance\");\n",
+    "        */\n",
+    "        table_content.push('</tr>');\n",
+    "\n",
+    "      }\n",
+    "      \n",
+    "      document.getElementById(\"table_materials_submitted_info\").innerHTML = table_content.join('');\n",
+    "    }\n",
+    "\n",
+    "    function clean_materials_selection()\n",
+    "    {\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_material\");\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "      {\n",
+    "        //choices_compare[i].removeAttribute('checked');\n",
+    "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+    "        choices_compare[i].checked = \"\";\n",
+    "      }\n",
+    "    }\n",
+    "\n",
+    "    function select_all()\n",
+    "    {\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_material\");\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "      {\n",
+    "        //choices_compare[i].removeAttribute('checked');\n",
+    "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+    "        choices_compare[i].checked = \"checked\";\n",
+    "      }\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "\n",
+    "    function process()\n",
+    "    {\n",
+    "        //alert(\"Process:\"+band_paths)\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_js_plot'));\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_materials_submitted_info'));\n",
+    "        show_materials_submitted_info();\n",
+    "        document.getElementById(\"table_visualize\").innerHTML = \"\";\n",
+    "        str = N_materials.toString();\n",
+    "        document.getElementById(\"n_materials\").innerHTML = \"Number of materials submitted: \" + str + \"<font size = 1px color = #C0C0C0  > &nbsp Please press \\'Visualize\\' to visualize the band structure. </font>\";\n",
+    "        document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n",
+    "    }\n",
+    "        \n",
+    "\n",
+    "    var image_band = '';\n",
+    "    var image_dos = '';\n",
+    "    var image_band_links = new Array(N_materials); //store the URL of each band figure -> used to compare 2 figures\n",
+    "    var image_band_links_selected = [];\n",
+    "    var image_band_selected_Number = []; //record which i_material has been selected\n",
+    "\n",
+    "\n",
+    "\n",
+    "    function prepare(N_materials_show)\n",
+    "    {\n",
+    "      document.getElementById(\"table_visualize\").innerHTML = \"\";\n",
+    "      var table_content = new Array(); \n",
+    "      //document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n",
+    "      //-----Generate the html tables for each material--------\n",
+    "      for(var i = 0; i < N_materials_show; i++)\n",
+    "      {\n",
+    "        checkbox_material_id = \"checkbox_material\" + i.toString();\n",
+    "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+    "        if(if_selected != 1)\n",
+    "        {\n",
+    "          continue;\n",
+    "        }\n",
+    "\n",
+    "        table_content.push('<tr>');\n",
+    "        div_string = '<div style = \\\"height: 20px\\\"></div>';\n",
+    "        table_content.push(div_string);\n",
+    "        table_content.push('<th>');\n",
+    "\n",
+    "        //add main container div\n",
+    "        div_string = '<div id = \\\"div_band_dos' + i.toString() + '\\\" class = \\\"div_band_dos\\\" >';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //show No. of the material\n",
+    "        i_material = i + 1;\n",
+    "        div_string = '<div style = \\\"height:30px\\; font-size: 15pt;\">' + '#' + i_material.toString() + '</div>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //show band_path/dos info\n",
+    "        div_string = '<div style = \\\"height:30px\\\">' + 'Band: &nbsp&nbsp' + band_paths[i] + ',&nbsp&nbsp&nbsp&nbspDOS: &nbsp&nbsp' + dos_paths[i] + '</div>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add div_band\n",
+    "        div_string = '<div id = \\\"div_band' + i.toString() + '\\\" class = \\\"div_band\\\" ></div>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add div_dos\n",
+    "        div_string = '<div id = \\\"div_dos' + i.toString() + '\\\" class = \\\"div_dos\\\" ></div>';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add div_tools\n",
+    "        div_string = '<div id = \\\"div_tools' + i.toString() + '\\\" class = \\\"div_tools\\\" >';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add: infomation\n",
+    "        div_string = '<div id = \\\"div_info' + i.toString() + '\\\">atom_labels<br>program_name</div>';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add: custom scale\n",
+    "        div_string = '<br><p style=\\\"color: #000;font-weight: 100; font-size: 10pt; align:left\\\"> Set the lower and upper limit of energy scale (in eV): <br><br><font color=\\\"black\\\" size = 3px> Lower limit: &nbsp&nbsp </font><textarea  id=\\\"lowerlimit' + i.toString() + '\\\"  rows=\\\"1\\\" style = \\\"width: 70px;\\\">-10</textarea> <font color=\\\"black\\\" size = 3px> &nbsp eV</font> &nbsp&nbsp&nbsp<font color=\\\"black\\\" size = 3px> Upper limit: &nbsp&nbsp </font><textarea  id=\\\"upperlimit' + i.toString() + '\\\"  rows=\\\"1\\\" style = \\\"width: 70px;\\\">10</textarea> <font color=\\\"black\\\" size = 3px> &nbsp eV&nbsp&nbsp&nbsp</font></p>';\n",
+    "        table_content.push(div_string);\n",
+    "        div_string = '<br><button class = \\\"button_tools\\\" id = \\\"button_customscale' + i.toString() + '\\\"  onclick = \\\"customscale(this.id)\\\"> Rescale </button>';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "\n",
+    "        //add button:autoscale\n",
+    "        div_string = '<button class = \\\"button_tools\\\" id = \\\"button_autoscale' + i.toString() + '\\\"  onclick = \\\"autoscale(this.id)\\\" title = \\\"(-10 eV, 10 eV)\\\"> Autoscale </button>';    \n",
+    "        table_content.push(div_string);\n",
+    "        //add button:fullscale\n",
+    "        div_string = '<button class = \\\"button_tools\\\" id = \\\"button_fullscale' + i.toString() + '\\\"  onclick = \\\"fullscale(this.id)\\\" title = \\\"(-100 eV, 100 eV)\\\"> Full scale </button><br><br>';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //table_content.push(\"Select and zoom:\");\n",
+    "\n",
+    "        /*//overview for select and zoom\n",
+    "        div_string = '<div id = \\\"div_overview' + i.toString() + '\\\" class = \\\"div_overview\\\" ></div>';    //  <div id=\"overview\" style=\"width:300px;height:200px; margin-left:10px; margin-top: 50px; padding-top: 0px\"></div>\n",
+    "        table_content.push(div_string);\n",
+    "        div_string = '<p id = \\\"overviewLegend' + i.toString() + '\\\"  ></p>';    //  <p id=\"overviewLegend\" style=\"margin-left:10px\"></p>\n",
+    "        table_content.push(div_string);*/\n",
+    "\n",
+    "        //download figures as png\n",
+    "        div_string = '<a id = \\\"img_band' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download band </a>';\n",
+    "        table_content.push(div_string);    \n",
+    "        div_string = '<a id = \\\"img_dos' + i.toString() + '\\\" class = \\\"button_tools\\\"  target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download DOS </a>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add show VBM & CBM\n",
+    "        div_string = '<br><br><p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_VBM' + i.toString() + '\\\" unchecked  onclick=\\\"show_VBM(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Show VBM </font>  (<font color=\\\"blue\\\">\\•</font>) <font color=\\\"black\\\" size = 3px> and CBM </font>(<font color=\\\"red\\\">\\•</font>) </p>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "\n",
+    "        table_content.push('</div>');//div_tools\n",
+    "\n",
+    "        //checkbox for comparison\n",
+    "        div_string = '<div id = \\\"div_checkbox_compare' + i.toString() + '\\\" class = \\\"div_checkbox_compare\\\" >';\n",
+    "        table_content.push(div_string);\n",
+    "        //div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n",
+    "        div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" checked = \\\"unchecked\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n",
+    "        table_content.push(div_string);\n",
+    "        table_content.push('</div>');//div_checkbox_compare\n",
+    "\n",
+    "\n",
+    "        table_content.push('</div>');//div_band_dos\n",
+    "        table_content.push('</th>');\n",
+    "        table_content.push('</tr>'); \n",
+    "      }\n",
+    "\n",
+    "      document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    function visualize_band_dos()\n",
+    "    {\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_jquery'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_axislabels'));\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_dashes'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_navigate'));\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_selection'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_flot_legendoncanvas'));\n",
+    "        document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n",
+    "        document.getElementById(\"div_compare_buttons\").style.visibility=\"\";\n",
+    "\n",
+    "\n",
+    "\n",
+    "        if(N_materials > N_max_show)\n",
+    "        {\n",
+    "            document.getElementById(\"div_showall\").style.visibility=\"visible\";\n",
+    "            document.getElementById(\"checkbox_showall\").checked = \"\";\n",
+    "        }              \n",
+    "\n",
+    "        N_materials_show = Math.min(N_max_show, N_materials);\n",
+    "\n",
+    "        prepare(N_materials_show);\n",
+    "        clean_compare_list();\n",
+    "        plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    function show_all(id)//\"plot_placeholder\"\n",
+    "    {\n",
+    "        var if_showall=0;\n",
+    "        if_showall = check_show_VBM(id);\n",
+    "        if(if_showall == 1)\n",
+    "        {\n",
+    "            N_materials_show = N_materials;\n",
+    "            prepare(N_materials_show);\n",
+    "            clean_compare_list();\n",
+    "            plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+    "        }\n",
+    "        else\n",
+    "        {\n",
+    "            N_materials_show = Math.min(N_max_show, N_materials);\n",
+    "            prepare(N_materials_show);\n",
+    "            clean_compare_list();\n",
+    "            plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+    "        }\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    \n",
+    "    //------------------Tool used to get the content from textarea---------------------\n",
+    "    function get_text(textarea_id)\n",
+    "    {\n",
+    "      var text = document.getElementById(textarea_id).value;\n",
+    "      return text;\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "\n",
+    "    //-------------------Compare 2 band figures----------------------------------------\n",
+    "\n",
+    "\n",
+    "    function check_compare(id)//checkbox_compare' + i.toString() + '\\\" unchecked  onclick=\\\"check_compare(this.id)\n",
+    "    {\n",
+    "      var x = document.getElementById(id);\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+    "      var N_chosen = 0;\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "      {\n",
+    "        if(choices_compare[i].checked)\n",
+    "        {\n",
+    "          N_chosen ++;\n",
+    "        }\n",
+    "      }\n",
+    "      if(N_chosen == 2) // In max. only 2 figures could be selected and compared.\n",
+    "      {\n",
+    "        for(var i=0; i<choices_compare.length; i++)\n",
+    "        {\n",
+    "          if(!choices_compare[i].checked)\n",
+    "          {\n",
+    "            choices_compare[i].disabled = 'disabled';\n",
+    "          }\n",
+    "        }\n",
+    "      }\n",
+    "      else\n",
+    "      {\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "        {\n",
+    "          choices_compare[i].removeAttribute('disabled');\n",
+    "        }\n",
+    "      }\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    function compare()\n",
+    "    {\n",
+    "        $(\"#div_compare\").fadeIn(600);//show div for comparison\n",
+    "        //check_compare(-100);\n",
+    "\n",
+    "        var compare_list = [];\n",
+    "        compare_list = make_compare_list();\n",
+    "                //[i_material_1, i_material_2] = make_compare_list();\n",
+    "        i_material_1 = compare_list[0];\n",
+    "        i_material_2 = compare_list[1];\n",
+    "        //document.getElementById(\"demo\").innerHTML = \"In add info compare:\" + i_material_1.toString() + i_material_2.toString();\n",
+    "        compare_figures(i_material_1, i_material_2);  \n",
+    "    }\n",
+    "    function make_compare_list()\n",
+    "    {\n",
+    "      //get the links to the images\n",
+    "      images_selected_links = []; //store the links to the figures for comparison\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+    "      var N_chosen = 0;\n",
+    "      var str = ''; //tmp str for debug\n",
+    "      var figure_selected = new Array(2);\n",
+    "      for(var i=0; i<choices_compare.length; i++) //check which figures are selected\n",
+    "      {\n",
+    "        if(choices_compare[i].checked)\n",
+    "        {\n",
+    "          id_chosen = choices_compare[i].id;\n",
+    "          i_chosen = Math.round(id_chosen.substring(16));\n",
+    "          var tmp_str = image_band_links[i_chosen];\n",
+    "          images_selected_links.push(tmp_str);\n",
+    "          figure_selected[N_chosen] = i_chosen;\n",
+    "          N_chosen ++;\n",
+    "          //str += beakerx.image_band_links[i];\n",
+    "        }\n",
+    "      }\n",
+    "      var i_material_1 = 0;\n",
+    "      var i_material_2 = 0;\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'In making comare list';\n",
+    "      image_band_links_selected = images_selected_links;\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'In making comare list: next';\n",
+    "      if(N_chosen == 2)\n",
+    "      {\n",
+    "        i_material_1 = figure_selected[0];\n",
+    "        i_material_2 = figure_selected[1];\n",
+    "      }\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'Compare_list: ' +i_material_1.toString() + ' ' + i_material_2.toString();\n",
+    "\n",
+    "      return [i_material_1, i_material_2];\n",
+    "    }\n",
+    "\n",
+    "    function check_compare_scale(i_material_1, i_material_2)\n",
+    "    {\n",
+    "      lowerlimit_id_1 = \"lowerlimit\" + i_material_1.toString();\n",
+    "      lowerlimit_id_2 = \"lowerlimit\" + i_material_2.toString();\n",
+    "      upperlimit_id_1 = \"upperlimit\" + i_material_1.toString();\n",
+    "      upperlimit_id_2 = \"upperlimit\" + i_material_2.toString();\n",
+    "\n",
+    "      lowerlimit_1 = parseFloat(document.getElementById(lowerlimit_id_1).innerHTML);\n",
+    "      lowerlimit_2 = parseFloat(document.getElementById(lowerlimit_id_2).innerHTML);\n",
+    "      upperlimit_1 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n",
+    "      upperlimit_2 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n",
+    "      if((lowerlimit_1 != lowerlimit_2) || (upperlimit_1 != upperlimit_2))\n",
+    "        return -1;\n",
+    "      else\n",
+    "        return 1;\n",
+    "    }\n",
+    "\n",
+    "    function compare_figures(i_material_1, i_material_2)\n",
+    "    {\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_query_beforeafter'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_compare_slide'));\n",
+    "        add_info_compare(i_material_1, i_material_2);\n",
+    "        document.getElementById(\"div_compare_container\").scrollIntoView({ behavior: 'smooth' }); \n",
+    "        document.getElementById(\"div_compare_container\").scrollTop += 50;\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    function clean_compare_list()\n",
+    "    {\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "      {\n",
+    "        //choices_compare[i].removeAttribute('checked');\n",
+    "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+    "        choices_compare[i].checked = \"\";\n",
+    "        choices_compare[i].removeAttribute('disabled');\n",
+    "      }\n",
+    "    }\n",
+    "\n",
+    "    //-----------Add information about the calculation to \"div_tools\"---------------\n",
+    "    function add_info(i)\n",
+    "    {\n",
+    "      \n",
+    "      //document.getElementById(\"demoa\").innerHTML = i.toString() + div_info_id;\n",
+    "      //for(var i = 0; i < beakerx.N_materials; i++)\n",
+    "      //{\n",
+    "      div_info_id = \"div_info\" + i.toString();\n",
+    "\n",
+    "      var str = '';\n",
+    "      str += \"<br> <p style=\\\"text-align:left\\\"><font size = 3pt><b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"atom_labels\"] + '</font></p>';\n",
+    "      //str += \"<font size = 3pt><b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"space_group_symbol\"] + '</font>';\n",
+    "      //str += \"<font size = 3pt><b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"lattice_constant\"] + '</font>';\n",
+    "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_name\"].toUpperCase() + '</font></p>';\n",
+    "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_basis_set_type\"] + '</font></p>';\n",
+    "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"XC_functional_name\"] + '</font></p>';\n",
+    "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3) + '</font></p>';\n",
+    "      document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n",
+    "      //document.getElementById('program_name_1').innerHTML = \"<b>Code:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"program_name\"];\n",
+    "      //document.getElementById('program_basis_set_type_1').innerHTML = \"<b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"program_basis_set_type\"];\n",
+    "      //document.getElementById('XC_functional_name_1').innerHTML = \"<b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"XC_functional_name\"];  \n",
+    "      //}\n",
+    "      \n",
+    "    }\n",
+    "    function add_info_compare(i,j)\n",
+    "    {\n",
+    "\n",
+    "      div_info_id = \"div_compare_info\";\n",
+    "      var str = '';\n",
+    "\n",
+    "      if_same_scale = check_compare_scale(i_material_1, i_material_2);\n",
+    "      if(if_same_scale == -1)\n",
+    "      {\n",
+    "        str = '<b><font size = \"15pt\" color=\"#940000\">Error: Different lower/upper limits.</font></b><br>';\n",
+    "        document.getElementById(\"div_compare_container\").innerHTML = str;\n",
+    "        document.getElementById(div_info_id).innerHTML = '';\n",
+    "        return;\n",
+    "      }\n",
+    "\n",
+    "      str += \"<br><b><font-size:15pt>Information of the first calculation (left):</font></b> <br>\";\n",
+    "      str += \"<br> <b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"atom_labels\"];\n",
+    "      //str += \"<br> <b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"space_group_symbol\"];\n",
+    "      //str += \"<br> <b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"lattice_constant\"];\n",
+    "      str += \"<br> <b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_name\"].toUpperCase();\n",
+    "      str += \"<br> <b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_basis_set_type\"];\n",
+    "      str += \"<br> <b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"XC_functional_name\"];\n",
+    "      str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+    "      str += \"<br><br><br><b><font-size:15pt>Information of the second calculation (right):</font></b><br>\";\n",
+    "      str += \"<br> <b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"atom_labels\"];\n",
+    "      //str += \"<br> <b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"space_group_symbol\"];\n",
+    "      //str += \"<br> <b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"lattice_constant\"];\n",
+    "      str += \"<br> <b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"program_name\"].toUpperCase();\n",
+    "      str += \"<br> <b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"program_basis_set_type\"];  \n",
+    "      str += \"<br> <b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"XC_functional_name\"];\n",
+    "      str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+    "      document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "\n",
+    "    //-----------------------Show/hide VBM, CBM-------------------------\n",
+    "    function check_show_VBM(checkbox_VBM_id)\n",
+    "    {\n",
+    "      var x = document.getElementById(checkbox_VBM_id);\n",
+    "      var if_checked = 0;\n",
+    "      if(x.checked)//== \"checked\")\n",
+    "      {\n",
+    "        //document.getElementById(\"demoa\").innerHTML = \"checked!\";\n",
+    "        if_checked = 1;\n",
+    "      }\n",
+    "      else if (x.unchecked)// == \"unchecked\")\n",
+    "      {\n",
+    "        //document.getElementById(\"demoa\").innerHTML = \"unchecked!\";\n",
+    "        if_checked = -1;\n",
+    "      }\n",
+    "      else\n",
+    "      {\n",
+    "        //document.getElementById(\"demoa\").innerHTML = \"nothing detected!\";\n",
+    "      }\n",
+    "      return if_checked;\n",
+    "    }\n",
+    "\n",
+    "    function check_if_in_compare_list(i) // check if the current material i is to be compared\n",
+    "    {\n",
+    "\n",
+    "      var checkbox_compare_id = \"checkbox_compare\" + i.toString();\n",
+    "      var if_compare = check_show_VBM(checkbox_compare_id);\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'if_compare of ' + i.toString() + ' : ' + if_compare.toString();\n",
+    "      var i_compare_material_1, i_compare_material_2;\n",
+    "      [i_compare_material_1, i_compare_material_2] = make_compare_list();\n",
+    "      var i_in_compare_list = -1;\n",
+    "      if(i_compare_material_1 == i)\n",
+    "      {\n",
+    "        i_in_compare_list = 1;\n",
+    "      }\n",
+    "      else if (i_compare_material_2 == i)\n",
+    "      {\n",
+    "        i_in_compare_list = 2;\n",
+    "      }\n",
+    "      else\n",
+    "      {\n",
+    "        i_in_compare_list = 0;\n",
+    "      }\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'Checking ' + i.toString() + ' in Compare_list:  ' + i_in_compare_list.toString();\n",
+    "      return [if_compare, i_in_compare_list];\n",
+    "    }\n",
+    "\n",
+    "    function show_VBM(id)\n",
+    "    {\n",
+    "      //prepare(\"new\");\n",
+    "      //var if_show_VBM = -1;\n",
+    "      var len_id = id.length;\n",
+    "      var i_material = id.substring(12);\n",
+    "      var i = Math.round(i_material);\n",
+    "\n",
+    "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "\n",
+    "      var if_compare, i_in_compare_list;\n",
+    "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+    "      //document.getElementById(\"demo\").innerHTML = i.toString() + ' in Compare_list:  ' + i_in_compare_list.toString();\n",
+    "\n",
+    "      plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    //---------------------Functions to rescale-------------------------------------------\n",
+    "    function autoscale(id)\n",
+    "    {\n",
+    "      var len_id = id.length;\n",
+    "      var i_material = id.substring(16);\n",
+    "      var i = Math.round(i_material);\n",
+    "\n",
+    "      upperlim_id = \"upperlimit\" + i_material;\n",
+    "      document.getElementById(upperlim_id).innerHTML =\"10.0\";\n",
+    "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+    "      document.getElementById(lowerlim_id).innerHTML =\"-10.0\";\n",
+    "\n",
+    "\n",
+    "      //document.getElementById(\"demoa\").innerHTML =i_material;\n",
+    "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "\n",
+    "      var if_compare, i_in_compare_list;\n",
+    "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+    "\n",
+    "\n",
+    "      plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    function fullscale(id)\n",
+    "    {\n",
+    "      var len_id = id.length;\n",
+    "      var i_material = id.substring(16);\n",
+    "      var i = Math.round(i_material);\n",
+    "\n",
+    "      upperlim_id = \"upperlimit\" + i_material;\n",
+    "      document.getElementById(upperlim_id).innerHTML =\"100.0\";\n",
+    "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+    "      document.getElementById(lowerlim_id).innerHTML =\"-100.0\";\n",
+    "\n",
+    "      //document.getElementById(\"demoa\").innerHTML =i_material;\n",
+    "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "\n",
+    "      var if_compare, i_in_compare_list;\n",
+    "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+    "\n",
+    "\n",
+    "\n",
+    "      plot_band_dos_i(i, -100, 100, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    function customscale(id)\n",
+    "    {\n",
+    "      var len_id = id.length;\n",
+    "      var i_material = id.substring(18);\n",
+    "      var i = Math.round(i_material);\n",
+    "      //\n",
+    "      upperlim_id = \"upperlimit\" + i_material;\n",
+    "      upperlim = document.getElementById(upperlim_id).value;\n",
+    "      upperlim_float = Math.round(upperlim);\n",
+    "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+    "      lowerlim = document.getElementById(lowerlim_id).value;\n",
+    "      lowerlim_float = Math.round(lowerlim);\n",
+    "\n",
+    "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "\n",
+    "      var if_compare, i_in_compare_list;\n",
+    "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+    "\n",
+    "\n",
+    "\n",
+    "      plot_band_dos_i(i, lowerlim_float, upperlim_float, if_show_VBM, if_compare, i_in_compare_list);  \n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    function plot_band_dos(lowerLim, upperLim, N_materials_show)\n",
+    "    {\n",
+    "      placeholder_band = \"#div_band1\";\n",
+    "      placeholder_dos = \"#div_dos1\";\n",
+    "     // lowerLim = -10.01\n",
+    "      //upperLim = 10.01\n",
+    "\n",
+    "\n",
+    "\n",
+    "      //alert(\"plot_band_dos\");\n",
+    "      //prepare();\n",
+    "      for(var i = 0; i < N_materials_show; i++)\n",
+    "      {\n",
+    "        \n",
+    "        var checkbox_material_id = \"checkbox_material\" + i.toString();\n",
+    "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+    "        if(if_selected != 1)\n",
+    "        {\n",
+    "          continue;\n",
+    "        }\n",
+    "        add_info(i);\n",
+    "      }\n",
+    "\n",
+    "      //------Plot----------------\n",
+    "        /*\n",
+    "      for(var i_material = 0; i_material < N_materials_show; i_material++)\n",
+    "      {\n",
+    "\n",
+    "        //alert(\"Material \"+i);\n",
+    "        var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n",
+    "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+    "        if(if_selected != 1)\n",
+    "        {\n",
+    "          continue;\n",
+    "        }\n",
+    "\n",
+    "        plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n",
+    "      }\n",
+    "        */\n",
+    "      //alert(\"next:for\")\n",
+    "      for (let i_material = 0, p = Promise.resolve(); i_material < N_materials_show; i_material++) {\n",
+    "        p = p.then(_ => new Promise(resolve =>\n",
+    "            setTimeout(function () {\n",
+    "                //alert(i_material)\n",
+    "                var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n",
+    "                var if_selected = check_show_VBM(checkbox_material_id);\n",
+    "                if(if_selected == 1)\n",
+    "                {\n",
+    "                    plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n",
+    "                }\n",
+    "                resolve();\n",
+    "            }, 0)\n",
+    "        ));\n",
+    "      }\n",
+    "\n",
+    "\n",
+    "      return 1;\n",
+    "    }\n",
+    "\n",
+    "    var i = 0\n",
+    "    var lowerLim = -10\n",
+    "    var upperLim = 10\n",
+    "    var if_show_VBM = 0\n",
+    "    var if_compare = 0\n",
+    "    var i_in_compare_list = -1\n",
+    "\n",
+    "\n",
+    "    \n",
+    "    function plot_band_dos_i(i_material, lowerLim_material, upperLim_material, if_show_VBM_material, if_compare_material, i_in_compare_list_material)\n",
+    "    {\n",
+    "        //alert(\"plot_band_dos_i\")\n",
+    "\n",
+    "        i = i_material;\n",
+    "        lowerLim = lowerLim_material;\n",
+    "        upperLim = upperLim_material;\n",
+    "        if_show_VBM = if_show_VBM_material;\n",
+    "        if_compare = if_compare_material;\n",
+    "        i_in_compare_list = i_in_compare_list_material;\n",
+    "        //alert(\"plot_band_dos_i: i_material: \"+i)\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_band'));\n",
+    "        //alert('i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list')\n",
+    "        //plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_dos'));\n",
+    "    }    \n",
+    "</script>\n",
+    "\n",
+    "                                \n",
+    "                                \n",
+    "<br><br>\n",
+    "<button  class=\"button\" onclick=\"process()\">Process data</button>\n",
+    "<br><br>\n",
+    "<div id = \"n_materials\" style = \"font-size: 18px; font-weight: 100; height: 60px; width: 100%;\"> Number of materials submitted: 0</div>\n",
+    "<div id = \"show_materials_submitted\" style = \"font-size: 20px; font-color: black;\"> </div>\n",
+    "\n",
+    "<div style = \"width :100%; height: 30px;\"></div> \n",
+    "<p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select materials to visualize the band structure and DOS:</p>\n",
+    "<div style = \"width :100%; height: 10px;\"></div> \n",
+    "<button class = \"button\" onclick = \"clean_materials_selection()\"> Clean selections </button> \n",
+    "<button class = \"button\" onclick = \"select_all()\"> Select all </button> \n",
+    "<button class = \"button\" onclick = \"visualize_band_dos()\"> Visualize </button> \n",
+    "<div style = \"width :100%; height: 30px;\"></div> \n",
+    "\n",
+    "<div id = \"show_materials_submitted_info\" style = \"width: 100%; font-size: 20px; font-color: black;\"> \n",
+    "  <table id = \"table_materials_submitted_info\" style=\"width:100%\"> </table>\n",
+    "</div>\n",
+    "\n",
+    "<div style = \"width :100%; height: 30px;\"></div> \n",
+    "\n",
+    "\n",
+    "\n",
+    "\n",
+    "<div id=\"div_compare_buttons\" style=\"visibility:hidden\">\n",
+    "  <br><br><br>\n",
+    "  <p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select two materials in the checkbox on the right for comparison:</p>\n",
+    "  <p style=\"color: #000;font-weight: 1000; font-size: 8pt;\"></p>\n",
+    "  <button class = \"button\" onclick = \"clean_compare_list()\"> Clean selections </button> \n",
+    "  <button class = \"button\" onclick = \"compare();compare()\" title = \"Select 2 materials in the checkbox below and compare: please make sure that the upper/lower limits are the same (using Rescale/Autoscale buttons).\" > Compare</button>\n",
+    "</div>\n",
+    "\n",
+    "\n",
+    "\n",
+    "<div id = \"div_showall\" style = \"width: 100%; visibility:hidden\">\n",
+    "  <div style = \"width: 100%; height: 30px; \"></div>\n",
+    "  <input type = \"checkbox\" id = \"checkbox_showall\" unchecked onclick=\"show_all(this.id)\"/> <font color=\"black\" size = 3px> Show all results </font><font size = 2px color = \"#666\"> (By default only the first 10 results are shown.) </font> \n",
+    "  <div style = \"width: 100%; height: 30px; \"></div>\n",
+    "</div>\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n",
+    "<div id = \"div_compare\" style = \"position: fixed; top: 20%; left: 10%; width: 1200px; height: 600px; z-index: 999999; border: 1px solid #555; background-color: #fff; display: none\" onclick = \"$(this).fadeOut(500)\"> \n",
+    "  \n",
+    "  <div style = \"float: right; width: 80px; height: 25px; margin-top: 10px; margin-right: 10px; z-index: 1000000; border: 1px solid #555; text-align: center; vertical-align: middle; background-color: #f9f9f9; font-size:12pt; font-color: #000; cursor:pointer;\" > CLOSE </div> <!--button to close the div-->\n",
+    "  <div id = \"div_compare_info\" style = \" width: 350px; height: 500px; float: right; margin-top: 50px; margin-right: 10px; z-index: 10000000;\"></div>\n",
+    "  <div id = \"div_compare_container\" style = \"margin-top: 50px; margin-left: 100px; width: 600px; height: 300px;\">\n",
+    "    <div class=\"g-before-after\" id = \"div_compare_containerx\"></div>\n",
+    "  </div>\n",
+    "</div>\n",
+    "\n",
+    "\n",
+    "<div id = \"demo\"></div>\n",
+    "\n",
+    "<div id = \"plot_placeholder\">\n",
+    "    <div><br></div>\n",
+    "    <table id = \"table_visualize\"> </table>\n",
+    "</div>\n",
+    "<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {
+    "tags": [
+     "plot_band"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "        //alert(\"tag: plot_band\")\n",
+       "\n",
+       "plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "\n",
+       "function plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n",
+       "{\n",
+       "        //i=0;\n",
+       "        //alert(\"plot_band \"+ i)\n",
+       "        var placeholder_band = \"#div_band\" + i.toString();\n",
+       "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+       "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+       "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+       "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+       "        var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "        var img_band_id = \"img_band\" + i.toString();\n",
+       "        var img_dos_id = \"img_dos\" + i.toString();\n",
+       "\n",
+       "        var placeholder_band_compare = \"\";\n",
+       "\n",
+       "\n",
+       "        if(i_in_compare_list == 1)\n",
+       "        {\n",
+       "            placeholder_band_compare = \"#div_band_compare_1\";\n",
+       "        }\n",
+       "        else if(i_in_compare_list == 2)\n",
+       "        {\n",
+       "            placeholder_band_compare = \"#div_band_compare_2\";\n",
+       "        }\n",
+       "        else\n",
+       "        {\n",
+       "            placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n",
+       "        }\n",
+       "\n",
+       "        Object.size = function(obj) {\n",
+       "            var size = 0, key;\n",
+       "            for (key in obj) \n",
+       "            {\n",
+       "                if (obj.hasOwnProperty(key)) size++;\n",
+       "            }\n",
+       "            return size;\n",
+       "        };\n",
+       "\n",
+       "        //Get the number of bands\n",
+       "        //alert(\"Getting band\")\n",
+       "        //alert(band_obj_all)\n",
+       "        //alert(\"band_obj_all got!\")\n",
+       "        var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n",
+       "        var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n",
+       "        //alert(band_obj_all[i][\"band_y_axis\"])\n",
+       "        var band_plotdata = [];\n",
+       "        \n",
+       "        for(var i_band =0; i_band < N_bands; i_band++)\n",
+       "        {\n",
+       "          var tmp_data = [];\n",
+       "          for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n",
+       "          {\n",
+       "            tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n",
+       "          }\n",
+       "          var plotData = { shadowSize: 0 , data: tmp_data, color: 'black',  series: { lines: { show: true } , points: {show: false} } };\n",
+       "          band_plotdata.push(plotData);\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        var tmp_data0 = [[0, 0], [1, 0]];\n",
+       "        var plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n",
+       "        band_plotdata.push(plotData0);\n",
+       "\n",
+       "        var band_plotdata_overview = band_plotdata.slice(0);\n",
+       "\n",
+       "        var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n",
+       "        var HOMOlabel = [\"VBM\"];\n",
+       "        var plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false},  showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+       "\n",
+       "        var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n",
+       "        var LUMOlabel = [\"CBM\"];\n",
+       "        var plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false},  showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+       "\n",
+       "        //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "        if (if_show_VBM == 1)\n",
+       "        {\n",
+       "          band_plotdata.push(plotHOMO);\n",
+       "          band_plotdata.push(plotLUMO);\n",
+       "        }\n",
+       "\n",
+       " \n",
+       "        //alert(img_band_id + band_plotdata)\n",
+       "            \n",
+       "        //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n",
+       "        //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\"  }\n",
+       "\n",
+       "        var canvas_band;\n",
+       "        var options_band = {\n",
+       "          canvas: true,\n",
+       "          //legend:{ type: \"canvas\" },\n",
+       "          series: { lines: { show: true, lineWidth: 2 }, \n",
+       "          points: { show: false } }, \n",
+       "          xaxis: { \n",
+       "            ticks: band_obj_all[i][\"labels\"], \n",
+       "            color:\"#000\", \n",
+       "            font: {size: 20}, \n",
+       "            zoomRange: false,\n",
+       "            panRange: false \n",
+       "          }, \n",
+       "          yaxis: { \n",
+       "            axisLabel: \"Energy (eV)\", \n",
+       "            axisLabelUseCanvas: true,\n",
+       "            //axisLabelUseCanvas: false,\n",
+       "            axisLabelFontSizePixels: 20,\n",
+       "            axisLabelFontFamily: 'Arial', \n",
+       "            axisLabelPadding: 10, \n",
+       "            color:\"#000\", \n",
+       "            font: {size: 20, family:\"Arial\"},\n",
+       "            tickLength:-5, \n",
+       "            min: lowerLim, \n",
+       "            max: upperLim,\n",
+       "            tickDecimals: 0, \n",
+       "            zoomRange: [0.001, 1000],\n",
+       "            panRange: [-100, 100] \n",
+       "          },\n",
+       "\n",
+       "          zoom: { \n",
+       "            interactive: true\n",
+       "          },\n",
+       "\n",
+       "          pan: {\n",
+       "            interactive: true\n",
+       "          }, \n",
+       "\n",
+       "          //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n",
+       "\n",
+       "          grid: { \n",
+       "            labelMargin: 15,\n",
+       "            hoverable: true, \n",
+       "            backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n",
+       "            borderWidth: {\n",
+       "              top: 2, \n",
+       "              right: 2,\n",
+       "              bottom: 2,\n",
+       "              left: 2,\n",
+       "              color : null } \n",
+       "          }\n",
+       "        }\n",
+       "        //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n",
+       "        //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n",
+       "        var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n",
+       "        var image_band = plot_band.toDataURL();\n",
+       "        image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n",
+       "        //beakerx.image_band = image_band;\n",
+       "        document.getElementById(img_band_id).href= image_band;\n",
+       "        image_band_links[i] = image_band;\n",
+       "        //alert(\"band done\")\n",
+       "}\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "        //alert(\"tag: plot_band\")\n",
+    "\n",
+    "plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "\n",
+    "function plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n",
+    "{\n",
+    "        //i=0;\n",
+    "        //alert(\"plot_band \"+ i)\n",
+    "        var placeholder_band = \"#div_band\" + i.toString();\n",
+    "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+    "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+    "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+    "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+    "        var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "        var img_band_id = \"img_band\" + i.toString();\n",
+    "        var img_dos_id = \"img_dos\" + i.toString();\n",
+    "\n",
+    "        var placeholder_band_compare = \"\";\n",
+    "\n",
+    "\n",
+    "        if(i_in_compare_list == 1)\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_1\";\n",
+    "        }\n",
+    "        else if(i_in_compare_list == 2)\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_2\";\n",
+    "        }\n",
+    "        else\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n",
+    "        }\n",
+    "\n",
+    "        Object.size = function(obj) {\n",
+    "            var size = 0, key;\n",
+    "            for (key in obj) \n",
+    "            {\n",
+    "                if (obj.hasOwnProperty(key)) size++;\n",
+    "            }\n",
+    "            return size;\n",
+    "        };\n",
+    "\n",
+    "        //Get the number of bands\n",
+    "        //alert(\"Getting band\")\n",
+    "        //alert(band_obj_all)\n",
+    "        //alert(\"band_obj_all got!\")\n",
+    "        var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n",
+    "        var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n",
+    "        //alert(band_obj_all[i][\"band_y_axis\"])\n",
+    "        var band_plotdata = [];\n",
+    "        \n",
+    "        for(var i_band =0; i_band < N_bands; i_band++)\n",
+    "        {\n",
+    "          var tmp_data = [];\n",
+    "          for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n",
+    "          {\n",
+    "            tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n",
+    "          }\n",
+    "          var plotData = { shadowSize: 0 , data: tmp_data, color: 'black',  series: { lines: { show: true } , points: {show: false} } };\n",
+    "          band_plotdata.push(plotData);\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        var tmp_data0 = [[0, 0], [1, 0]];\n",
+    "        var plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n",
+    "        band_plotdata.push(plotData0);\n",
+    "\n",
+    "        var band_plotdata_overview = band_plotdata.slice(0);\n",
+    "\n",
+    "        var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n",
+    "        var HOMOlabel = [\"VBM\"];\n",
+    "        var plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false},  showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+    "\n",
+    "        var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n",
+    "        var LUMOlabel = [\"CBM\"];\n",
+    "        var plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false},  showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+    "\n",
+    "        //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "        if (if_show_VBM == 1)\n",
+    "        {\n",
+    "          band_plotdata.push(plotHOMO);\n",
+    "          band_plotdata.push(plotLUMO);\n",
+    "        }\n",
+    "\n",
+    " \n",
+    "        //alert(img_band_id + band_plotdata)\n",
+    "            \n",
+    "        //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n",
+    "        //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\"  }\n",
+    "\n",
+    "        var canvas_band;\n",
+    "        var options_band = {\n",
+    "          canvas: true,\n",
+    "          //legend:{ type: \"canvas\" },\n",
+    "          series: { lines: { show: true, lineWidth: 2 }, \n",
+    "          points: { show: false } }, \n",
+    "          xaxis: { \n",
+    "            ticks: band_obj_all[i][\"labels\"], \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20}, \n",
+    "            zoomRange: false,\n",
+    "            panRange: false \n",
+    "          }, \n",
+    "          yaxis: { \n",
+    "            axisLabel: \"Energy (eV)\", \n",
+    "            axisLabelUseCanvas: true,\n",
+    "            //axisLabelUseCanvas: false,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial', \n",
+    "            axisLabelPadding: 10, \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20, family:\"Arial\"},\n",
+    "            tickLength:-5, \n",
+    "            min: lowerLim, \n",
+    "            max: upperLim,\n",
+    "            tickDecimals: 0, \n",
+    "            zoomRange: [0.001, 1000],\n",
+    "            panRange: [-100, 100] \n",
+    "          },\n",
+    "\n",
+    "          zoom: { \n",
+    "            interactive: true\n",
+    "          },\n",
+    "\n",
+    "          pan: {\n",
+    "            interactive: true\n",
+    "          }, \n",
+    "\n",
+    "          //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n",
+    "\n",
+    "          grid: { \n",
+    "            labelMargin: 15,\n",
+    "            hoverable: true, \n",
+    "            backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n",
+    "            borderWidth: {\n",
+    "              top: 2, \n",
+    "              right: 2,\n",
+    "              bottom: 2,\n",
+    "              left: 2,\n",
+    "              color : null } \n",
+    "          }\n",
+    "        }\n",
+    "        //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n",
+    "        //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n",
+    "        var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n",
+    "        var image_band = plot_band.toDataURL();\n",
+    "        image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n",
+    "        //beakerx.image_band = image_band;\n",
+    "        document.getElementById(img_band_id).href= image_band;\n",
+    "        image_band_links[i] = image_band;\n",
+    "        //alert(\"band done\")\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {
+    "tags": [
+     "plot_dos"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "        //alert(\"tag: plot_dos \" + i)\n",
+       "        //i=0;\n",
+       "\n",
+       "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+       "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+       "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+       "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+       "        var img_dos_id = \"img_dos\" + i.toString();\n",
+       "\n",
+       "//----Plot DOS----------------------\n",
+       "        var dos_plotdata = [];\n",
+       "        //alert(\"dos:\"+dos_obj_all[i])\n",
+       "        var xdos = dos_obj_all[i][\"dos_x_axis\"];\n",
+       "        var ydos = dos_obj_all[i][\"dos_y_axis\"][0];\n",
+       "        var dosLabelPos = Math.max.apply(Math, ydos)/2;\n",
+       "        var d2 = [];\n",
+       "        for (var ii = 0; ii < xdos.length; ii+=1) {\n",
+       "          d2.push([ydos[ii],xdos[ii]]);\n",
+       "        }\n",
+       "        var plotData2={ shadowSize: 0, color: 'black' , data: d2};\n",
+       "        dos_plotdata.push(plotData2);\n",
+       "        //alert(\"dos_plotdata\"+JSON.stringify(dos_plotdata[0]));\n",
+       "        \n",
+       "        function find_xaxis_max_min(data, lowerbound, upperbound)\n",
+       "        {\n",
+       "                //data[xaxis,y] find the max and min value of x axis\n",
+       "                //alert(\"dos[0]:\" + data[0][\"data\"]);\n",
+       "                //alert(\"Bounds: \" + lowerbound + \" ,  \" + upperbound)\n",
+       "                var n_data = data.length;\n",
+       "                //alert(\"N dos: \" + n_data);\n",
+       "                var data_min = 1000000;\n",
+       "                var data_max = -1000000;\n",
+       "                var data_current = 0;\n",
+       "                for (var i = 0; i < n_data; i++)\n",
+       "                {\n",
+       "                    if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n",
+       "                    {\n",
+       "                        data_current = data[i][0];\n",
+       "                        //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n",
+       "                        if(data_current >= data_max)\n",
+       "                        {\n",
+       "                            data_max = data_current;\n",
+       "                        }\n",
+       "                        if(data_current <= data_min)\n",
+       "                        {\n",
+       "                            data_min = data_current;\n",
+       "                        }\n",
+       "                    }\n",
+       "                }\n",
+       "                var data_max_min = [data_max, data_min];\n",
+       "                //alert(\"data_max_min: \" + data_max_min);\n",
+       "                return data_max_min;\n",
+       "        }\n",
+       "        var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n",
+       "        var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n",
+       "        //alert(\"dos_x_max_min:\"+dos_x_max_min+\", dosLabelPos:\"+dosLabelPos);\n",
+       "        var options_dos ={\n",
+       "          canvas: true,\n",
+       "          series: {\n",
+       "            lines: { show: true, lineWidth:2 },\n",
+       "            points: { show: false }\n",
+       "          },\n",
+       "\n",
+       "          yaxis: { \n",
+       "            axisLabel: \"\", \n",
+       "            axisLabelUseCanvas: true,\n",
+       "            axisLabelFontSizePixels: 20,\n",
+       "            axisLabelFontFamily: 'Arial', \n",
+       "            axisLabelPadding: 10, \n",
+       "            color:\"#000\", \n",
+       "            font: {size: 20},\n",
+       "            tickLength:-5, \n",
+       "            min: lowerLim, \n",
+       "            max: upperLim,\n",
+       "            tickDecimals: 0, \n",
+       "            zoomRange: [0.001, 1000],\n",
+       "            panRange: [-100, 100] \n",
+       "          },\n",
+       "\n",
+       "          xaxis: {\n",
+       "            axisLabel: \" \",\n",
+       "            axisLabelUseCanvas: false,\n",
+       "            axisLabelFontSizePixels: 20,\n",
+       "            axisLabelFontFamily: 'Arial',\n",
+       "            axisLabelPadding: 3,\n",
+       "            color:\"rgb(0, 0, 0)\",\n",
+       "            font: {size: 20, family:\"Arial\"},\n",
+       "            //ticks: 10,\n",
+       "            tickLength:0,\n",
+       "            min: dos_x_max_min[1],//0,\n",
+       "            max: dos_x_max_min[0],//1,\n",
+       "            tickDecimals: 0,\n",
+       "            ticks: [[ dosLabelPos ,'DOS']],\n",
+       "            //tickFormatter: MyFormatter\n",
+       "            panRange: false\n",
+       "          },\n",
+       "          pan: {\n",
+       "            interactive: true\n",
+       "          }, \n",
+       "\n",
+       "          grid: {\n",
+       "            labelMargin: 15,\n",
+       "            hoverable: true,\n",
+       "            //borderWidth : 1000,\n",
+       "            //show : false,\n",
+       "            //  //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n",
+       "            backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n",
+       "            borderWidth: {\n",
+       "              top: 2,\n",
+       "              right: 2,\n",
+       "              bottom: 2,\n",
+       "              left: 2,\n",
+       "              color : null\n",
+       "            }\n",
+       "          }\n",
+       "        }\n",
+       "        var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n",
+       "        var image_dos = plot_dos.toDataURL();\n",
+       "        image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n",
+       "        image_dos = image_dos;\n",
+       "        document.getElementById(img_dos_id).href= image_dos;\n",
+       "        //alert(\"dos done.\")\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "        //alert(\"tag: plot_dos \" + i)\n",
+    "        //i=0;\n",
+    "\n",
+    "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+    "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+    "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+    "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+    "        var img_dos_id = \"img_dos\" + i.toString();\n",
+    "\n",
+    "//----Plot DOS----------------------\n",
+    "        var dos_plotdata = [];\n",
+    "        //alert(\"dos:\"+dos_obj_all[i])\n",
+    "        var xdos = dos_obj_all[i][\"dos_x_axis\"];\n",
+    "        var ydos = dos_obj_all[i][\"dos_y_axis\"][0];\n",
+    "        var dosLabelPos = Math.max.apply(Math, ydos)/2;\n",
+    "        var d2 = [];\n",
+    "        for (var ii = 0; ii < xdos.length; ii+=1) {\n",
+    "          d2.push([ydos[ii],xdos[ii]]);\n",
+    "        }\n",
+    "        var plotData2={ shadowSize: 0, color: 'black' , data: d2};\n",
+    "        dos_plotdata.push(plotData2);\n",
+    "        //alert(\"dos_plotdata\"+JSON.stringify(dos_plotdata[0]));\n",
+    "        \n",
+    "        function find_xaxis_max_min(data, lowerbound, upperbound)\n",
+    "        {\n",
+    "                //data[xaxis,y] find the max and min value of x axis\n",
+    "                //alert(\"dos[0]:\" + data[0][\"data\"]);\n",
+    "                //alert(\"Bounds: \" + lowerbound + \" ,  \" + upperbound)\n",
+    "                var n_data = data.length;\n",
+    "                //alert(\"N dos: \" + n_data);\n",
+    "                var data_min = 1000000;\n",
+    "                var data_max = -1000000;\n",
+    "                var data_current = 0;\n",
+    "                for (var i = 0; i < n_data; i++)\n",
+    "                {\n",
+    "                    if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n",
+    "                    {\n",
+    "                        data_current = data[i][0];\n",
+    "                        //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n",
+    "                        if(data_current >= data_max)\n",
+    "                        {\n",
+    "                            data_max = data_current;\n",
+    "                        }\n",
+    "                        if(data_current <= data_min)\n",
+    "                        {\n",
+    "                            data_min = data_current;\n",
+    "                        }\n",
+    "                    }\n",
+    "                }\n",
+    "                var data_max_min = [data_max, data_min];\n",
+    "                //alert(\"data_max_min: \" + data_max_min);\n",
+    "                return data_max_min;\n",
+    "        }\n",
+    "        var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n",
+    "        var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n",
+    "        //alert(\"dos_x_max_min:\"+dos_x_max_min+\", dosLabelPos:\"+dosLabelPos);\n",
+    "        var options_dos ={\n",
+    "          canvas: true,\n",
+    "          series: {\n",
+    "            lines: { show: true, lineWidth:2 },\n",
+    "            points: { show: false }\n",
+    "          },\n",
+    "\n",
+    "          yaxis: { \n",
+    "            axisLabel: \"\", \n",
+    "            axisLabelUseCanvas: true,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial', \n",
+    "            axisLabelPadding: 10, \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20},\n",
+    "            tickLength:-5, \n",
+    "            min: lowerLim, \n",
+    "            max: upperLim,\n",
+    "            tickDecimals: 0, \n",
+    "            zoomRange: [0.001, 1000],\n",
+    "            panRange: [-100, 100] \n",
+    "          },\n",
+    "\n",
+    "          xaxis: {\n",
+    "            axisLabel: \" \",\n",
+    "            axisLabelUseCanvas: false,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial',\n",
+    "            axisLabelPadding: 3,\n",
+    "            color:\"rgb(0, 0, 0)\",\n",
+    "            font: {size: 20, family:\"Arial\"},\n",
+    "            //ticks: 10,\n",
+    "            tickLength:0,\n",
+    "            min: dos_x_max_min[1],//0,\n",
+    "            max: dos_x_max_min[0],//1,\n",
+    "            tickDecimals: 0,\n",
+    "            ticks: [[ dosLabelPos ,'DOS']],\n",
+    "            //tickFormatter: MyFormatter\n",
+    "            panRange: false\n",
+    "          },\n",
+    "          pan: {\n",
+    "            interactive: true\n",
+    "          }, \n",
+    "\n",
+    "          grid: {\n",
+    "            labelMargin: 15,\n",
+    "            hoverable: true,\n",
+    "            //borderWidth : 1000,\n",
+    "            //show : false,\n",
+    "            //  //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n",
+    "            backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n",
+    "            borderWidth: {\n",
+    "              top: 2,\n",
+    "              right: 2,\n",
+    "              bottom: 2,\n",
+    "              left: 2,\n",
+    "              color : null\n",
+    "            }\n",
+    "          }\n",
+    "        }\n",
+    "        var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n",
+    "        var image_dos = plot_dos.toDataURL();\n",
+    "        image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n",
+    "        image_dos = image_dos;\n",
+    "        document.getElementById(img_dos_id).href= image_dos;\n",
+    "        //alert(\"dos done.\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {
+    "tags": [
+     "init_jquery"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"http://code.jquery.com/jquery-1.8.3.min.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"http://code.jquery.com/jquery-1.8.3.min.js\"></script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {
+    "tags": [
+     "init_flot"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"js/jquery.flot.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"js/jquery.flot.js\"></script>\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {
+    "tags": [
+     "init_flot_axislabels"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"js/jquery.flot.axislabels.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"js/jquery.flot.axislabels.js\"></script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {
+    "tags": [
+     "init_flot_navigate"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"js/jquery.flot.navigate.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"js/jquery.flot.navigate.js\"></script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 87,
+   "metadata": {
+    "tags": [
+     "init_flot_selection"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"js/jquery.flot.selection.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"js/jquery.flot.selection.js\"></script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 51,
+   "metadata": {
+    "tags": [
+     "js_query_beforeafter"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "//jquery.beforeafter.min.js\n",
+       "!function(e){e.fn.beforeafter=function(i){var t=e.extend({touch:!0,message:\"Slide\",hide_message:!0,reset:!0,reset_delay:3e3,drag_horizontal:!0,split_horizontal:!0\n",
+       "},i);return this.each(function(){var i=e(this),a=i.find(\"img\"),n=a.data(\"aftersrc\"),s=i.width(),d=0;a.after('<div class=\"g-img-after\"><img style=\"width: '+s+'px;\" src=\"'+n+'\"></div>'),\n",
+       "a.addClass(\"g-img-before\").width(s),i.append('<div class=\"g-img-divider\"><span>'+t.message+\"</span></div>\"),d=i.height(),t.split_horizontal||i.addClass(\"g-vertical\"),\n",
+       "i.on(\"mouseenter touchstart\",function(e){var t=i.data(\"reset-timer\");t&&(window.clearTimeout(t),i.data(\"reset-timer\",!1))}).on(\"mousemove touchmove\",function(a){\n",
+       "var n=0,o=0,r=i.find(\".g-img-divider span\");if(t.drag_horizontal)n=a.pageX-i.offset().left,o=n/s*100;else{var f=i.offset().top-e(window).scrollTop();n=a.clientY/f,\n",
+       "o=(a.clientY-f)/d*100}if(t.touch&&\"undefined\"!=typeof a.originalEvent.touches){var g=a.originalEvent.touches[0];o=t.drag_horizontal?(g.pageX-i.offset().left)/s*100:(g.pageY-i.offset().top)/d*100;\n",
+       "}t.split_horizontal?(i.find(\".g-img-after\").css(\"left\",o+\"%\"),i.find(\".g-img-divider\").css(\"left\",o+\"%\")):(i.find(\".g-img-after\").css(\"top\",o+\"%\"),i.find(\".g-img-divider\").css(\"top\",o+\"%\")),\n",
+       "t.hide_message&&r.is(\":visible\")&&r.fadeOut()}).on(\"mouseleave touchend touchcancel\",function(e){var a=i.data(\"reset-timer\"),n=i.find(\".g-img-divider span\");\n",
+       "t.reset&&(a||(a=window.setTimeout(function(){t.split_horizontal?(i.find(\".g-img-after\").animate({left:\"50%\"},500),i.find(\".g-img-divider\").animate({left:\"50%\"\n",
+       "},500,function(){n.fadeIn()})):(i.find(\".g-img-after\").animate({top:\"50%\"},500),i.find(\".g-img-divider\").animate({top:\"50%\"},500,function(){n.fadeIn()})),\n",
+       "i.data(\"reset-timer\",!1)},t.reset_delay),i.data(\"reset-timer\",a)))})}),this}}(jQuery);\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "//jquery.beforeafter.min.js\n",
+    "!function(e){e.fn.beforeafter=function(i){var t=e.extend({touch:!0,message:\"Slide\",hide_message:!0,reset:!0,reset_delay:3e3,drag_horizontal:!0,split_horizontal:!0\n",
+    "},i);return this.each(function(){var i=e(this),a=i.find(\"img\"),n=a.data(\"aftersrc\"),s=i.width(),d=0;a.after('<div class=\"g-img-after\"><img style=\"width: '+s+'px;\" src=\"'+n+'\"></div>'),\n",
+    "a.addClass(\"g-img-before\").width(s),i.append('<div class=\"g-img-divider\"><span>'+t.message+\"</span></div>\"),d=i.height(),t.split_horizontal||i.addClass(\"g-vertical\"),\n",
+    "i.on(\"mouseenter touchstart\",function(e){var t=i.data(\"reset-timer\");t&&(window.clearTimeout(t),i.data(\"reset-timer\",!1))}).on(\"mousemove touchmove\",function(a){\n",
+    "var n=0,o=0,r=i.find(\".g-img-divider span\");if(t.drag_horizontal)n=a.pageX-i.offset().left,o=n/s*100;else{var f=i.offset().top-e(window).scrollTop();n=a.clientY/f,\n",
+    "o=(a.clientY-f)/d*100}if(t.touch&&\"undefined\"!=typeof a.originalEvent.touches){var g=a.originalEvent.touches[0];o=t.drag_horizontal?(g.pageX-i.offset().left)/s*100:(g.pageY-i.offset().top)/d*100;\n",
+    "}t.split_horizontal?(i.find(\".g-img-after\").css(\"left\",o+\"%\"),i.find(\".g-img-divider\").css(\"left\",o+\"%\")):(i.find(\".g-img-after\").css(\"top\",o+\"%\"),i.find(\".g-img-divider\").css(\"top\",o+\"%\")),\n",
+    "t.hide_message&&r.is(\":visible\")&&r.fadeOut()}).on(\"mouseleave touchend touchcancel\",function(e){var a=i.data(\"reset-timer\"),n=i.find(\".g-img-divider span\");\n",
+    "t.reset&&(a||(a=window.setTimeout(function(){t.split_horizontal?(i.find(\".g-img-after\").animate({left:\"50%\"},500),i.find(\".g-img-divider\").animate({left:\"50%\"\n",
+    "},500,function(){n.fadeIn()})):(i.find(\".g-img-after\").animate({top:\"50%\"},500),i.find(\".g-img-divider\").animate({top:\"50%\"},500,function(){n.fadeIn()})),\n",
+    "i.data(\"reset-timer\",!1)},t.reset_delay),i.data(\"reset-timer\",a)))})}),this}}(jQuery);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 52,
+   "metadata": {
+    "tags": [
+     "js_compare_slide"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "var div_str = '';\n",
+       "//div_str = '<style>  .g-before-after{position:relative;overflow:hidden}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%} </style>'\n",
+       "//div_str += '<script>$(\\'#div_compare_containerx\\').beforeafter();  </script>';\n",
+       "//div_str +='<script type=\\\"text/javascript\\\" src=\\\"https://github.com/jquery/jquery/blob/master/src/jquery.js\\\"></script> '\n",
+       "//div_str += '<div class=\\\"g-before-after\\\" id=\\\"div_compare_containerx\\\">';\n",
+       "div_str +='<img src = \\\"'\n",
+       "\n",
+       "var src1 = image_band_links_selected[0];\n",
+       "var src2 = image_band_links_selected[1];\n",
+       "var tmp_src1 = src1;\n",
+       "var tmp_src2 = src2;\n",
+       "//src1 = \"https://images4.alphacoders.com/640/640956.jpg\";\n",
+       "//src2 = \"http://imgmr.com/wp-content/uploads/2016/06/SAO-anime.jpg\";\n",
+       "div_str +=src1;\n",
+       "div_str += '\\\" data-aftersrc=\\\"'\n",
+       "div_str +=src2;\n",
+       "//div_str += '\\\"></div>';\n",
+       "div_str += '\\\"/>';\n",
+       "//#div_compare_containerx\n",
+       "document.getElementById(\"div_compare_containerx\").innerHTML = div_str;\n",
+       "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n",
+       "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n",
+       "//beakerx.image_band_links[i]\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "var div_str = '';\n",
+    "//div_str = '<style>  .g-before-after{position:relative;overflow:hidden}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%} </style>'\n",
+    "//div_str += '<script>$(\\'#div_compare_containerx\\').beforeafter();  </script>';\n",
+    "//div_str +='<script type=\\\"text/javascript\\\" src=\\\"https://github.com/jquery/jquery/blob/master/src/jquery.js\\\"></script> '\n",
+    "//div_str += '<div class=\\\"g-before-after\\\" id=\\\"div_compare_containerx\\\">';\n",
+    "div_str +='<img src = \\\"'\n",
+    "\n",
+    "var src1 = image_band_links_selected[0];\n",
+    "var src2 = image_band_links_selected[1];\n",
+    "var tmp_src1 = src1;\n",
+    "var tmp_src2 = src2;\n",
+    "//src1 = \"https://images4.alphacoders.com/640/640956.jpg\";\n",
+    "//src2 = \"http://imgmr.com/wp-content/uploads/2016/06/SAO-anime.jpg\";\n",
+    "div_str +=src1;\n",
+    "div_str += '\\\" data-aftersrc=\\\"'\n",
+    "div_str +=src2;\n",
+    "//div_str += '\\\"></div>';\n",
+    "div_str += '\\\"/>';\n",
+    "//#div_compare_containerx\n",
+    "document.getElementById(\"div_compare_containerx\").innerHTML = div_str;\n",
+    "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n",
+    "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n",
+    "//beakerx.image_band_links[i]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "scrolled": false,
+    "tags": [
+     "process_band_dos_data_python"
+    ]
+   },
+   "outputs": [],
+   "source": [
+    "#tag:python_2\n",
+    "import urllib.request, json\n",
+    "import numpy as np\n",
+    "import math\n",
+    "\n",
+    "#======Define global objs============\n",
+    "info_all = []\n",
+    "band_obj_all = []\n",
+    "dos_obj_all = []\n",
+    "\n",
+    "def load_jsonfile(path):\n",
+    "    #with open(path, encoding='utf-8') as band_file:    \n",
+    "    #    return json.load(band_file)\n",
+    "\n",
+    " \n",
+    "    with urllib.request.urlopen(path) as url:\n",
+    "        data = json.loads(url.read().decode())\n",
+    "    return data\n",
+    "\n",
+    "#-----Get the labels for x axis---------------\n",
+    "def get_label_flag(coor_array):\n",
+    "    #np.sort(coor_array)\n",
+    "    x = coor_array[0]\n",
+    "    y = coor_array[1]\n",
+    "    z = coor_array[2]\n",
+    "    coor =np.sort([x,y,z])\n",
+    "    xx = coor[0]\n",
+    "    yy = coor[1]\n",
+    "    zz = coor[2]\n",
+    "    coor = [xx, yy, zz]\n",
+    "    #pprint(coor)\n",
+    "    if (coor == [0, 0.5, 0.5]):\n",
+    "        return \"X\"\n",
+    "    if (coor == [0, 0.0, 0.5]):\n",
+    "        return \"M\"\n",
+    "    elif (coor == [0.5, 0.5, 0.5]):\n",
+    "        return \"L\"\n",
+    "    elif (coor == [0.375, 0.375, 0.75]):\n",
+    "        return \"K\"\n",
+    "    elif (coor == [0.25, 0.5, 0.75]):\n",
+    "        return \"W\"\n",
+    "    elif (coor == [0, 0, 0]):\n",
+    "        return \"\\u0393\"\n",
+    "    elif (coor == [0.25, 0.625, 0.625]):\n",
+    "        return \"U\"\n",
+    "    else:\n",
+    "        return \"?\"\n",
+    "\n",
+    "#============Process the band structure data============\n",
+    "def get_band_obj(band_path, dos_fermi_energy):\n",
+    "\n",
+    "    #band_data: read from json file    \n",
+    "    #Load the data files for band\n",
+    "    band_data = load_jsonfile(band_path)\n",
+    "   \n",
+    "    #---------Read section_k_band_segment------------\n",
+    "    section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n",
+    "    \n",
+    "    #--------Get the number of k band segments-------------\n",
+    "    N_k_band_segments = len(section_k_band_segment)\n",
+    "    \n",
+    "    #----------Get the total number of k points in all segments---------\n",
+    "    N_k_points_all = 0\n",
+    "    for i in range(N_k_band_segments):\n",
+    "        band_k_points = section_k_band_segment[i]['band_k_points']\n",
+    "        N_k_points_all = N_k_points_all + len(band_k_points)\n",
+    "    \n",
+    "    #--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n",
+    "    # store in k_coor_1D[N_k_points_total]-----------------\n",
+    "\n",
+    "    band_distance_segments = np.zeros(N_k_band_segments)\n",
+    "    for i in range(N_k_band_segments):\n",
+    "        [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end']  #\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n",
+    "        band_distance_segments[i] = math.pow((x1-x2), 2) + math.pow((y1-y2), 2) + math.pow((z1-z2), 2)\n",
+    "\n",
+    "    \n",
+    "    band_distance_total = math.fsum(band_distance_segments)\n",
+    "    #print(band_distance_segments)\n",
+    "    average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total\n",
+    "    \n",
+    "    #Prepare the parameters to rescale the k coordinates into [0,1]\n",
+    "    step_k_point = 1.0 / N_k_points_all\n",
+    "    step_k_point = (1.0 + step_k_point) / N_k_points_all\n",
+    "    \n",
+    "    #   \n",
+    "    k_coor_1D = np.zeros((N_k_points_all))\n",
+    "    for i_k_points in range(N_k_points_all):\n",
+    "        k_coor_1D[i_k_points] = round( step_k_point * i_k_points, 3)\n",
+    "    #for i in range(N_k_band_segments):\n",
+    "    #    ki[i] = \n",
+    "    \n",
+    "\n",
+    "    #--------Get the eigenvalues of each band trajectory--------------\n",
+    "    N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n",
+    "    N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n",
+    "    band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n",
+    "    N_k_points_all = 0\n",
+    "    for i_segments in range(N_k_band_segments):\n",
+    "        band_energies = section_k_band_segment[i_segments]['band_energies']\n",
+    "        N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n",
+    "        N_k_points_per_segment = len(band_energies[0])\n",
+    "        for i_k_points in range(N_k_points_per_segment):\n",
+    "            for i_bands in range(N_bands):\n",
+    "                band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n",
+    "            N_k_points_all = N_k_points_all + 1\n",
+    "    \n",
+    "    \n",
+    "    N_labels = 0\n",
+    "    for i_segments in range(N_k_band_segments):\n",
+    "        for j in range(2):\n",
+    "            labels_tmp =  section_k_band_segment[i_segments]['band_segm_start_end'][j];\n",
+    "            N_labels = N_labels + 1\n",
+    "\n",
+    "    label_flag = [\"\" for i in range(N_labels)] #stores the flags of the labels (X, W, G, etc)\n",
+    "\n",
+    "    i_label = 0\n",
+    "    label_flag_last_final = \"\"\n",
+    "    label_flag_current_initial = \"\"\n",
+    "    for i_segments in range(N_k_band_segments):\n",
+    "        labels_coor_0 =  section_k_band_segment[i_segments]['band_segm_start_end'][0];\n",
+    "        labels_coor_1 =  section_k_band_segment[i_segments]['band_segm_start_end'][1];\n",
+    "        np.sort(labels_coor_0)\n",
+    "        np.sort(labels_coor_1)\n",
+    "        label_flag_0 = get_label_flag(labels_coor_0)\n",
+    "        label_flag_1 = get_label_flag(labels_coor_1)\n",
+    "        label_flag_current_initial = label_flag_0\n",
+    "        if(label_flag_last_final == \"\"):\n",
+    "            label_flag_last_final = label_flag_0\n",
+    "\n",
+    "        if(label_flag_last_final == label_flag_current_initial):\n",
+    "            label_flag[i_label] = label_flag_current_initial\n",
+    "        else:\n",
+    "            label_flag[i_label] = \"\".join([label_flag_last_final, '|', label_flag_current_initial])\n",
+    "        label_flag_last_final = label_flag_1\n",
+    "    \n",
+    "\n",
+    "        i_label = i_label + 1\n",
+    "        if(i_segments == N_k_band_segments - 1):\n",
+    "            label_flag[i_label] = label_flag_1\n",
+    "            i_label = i_label + 1\n",
+    "\n",
+    "    N_labels = i_label\n",
+    "    \n",
+    "    #------------Get the coordinates for the labels------------\n",
+    "    #label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n",
+    "    label_coor_relative = np.zeros((N_labels))\n",
+    "    for i_label in range(N_labels):\n",
+    "        #Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n",
+    "        #x = labels_coor_0[0]\n",
+    "        #y = labels_coor_0[1]\n",
+    "        #z = labels_coor_0[2]\n",
+    "        #label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n",
+    "        label_coor_relative[i_label] = step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all);\n",
+    "\n",
+    "    #----Store the label-----------\n",
+    "    label_obj =[['' for i in range(2)] for j in range(N_labels)]\n",
+    "    for i_label in range(N_labels):\n",
+    "        label_obj[i_label][0] = label_coor_relative[i_label]\n",
+    "        label_obj[i_label][1] = label_flag[i_label]\n",
+    "        \n",
+    "    #print(label_obj)\n",
+    "        \n",
+    "  \n",
+    "    #Rescal the energies with respect to dos_fermi_energy\n",
+    "    for i_k_points in range(N_k_points_all):\n",
+    "        for i_bands in range(N_bands):\n",
+    "            band_energies_all[i_bands][i_k_points] =  band_energies_all[i_bands][i_k_points] - dos_fermi_energy\n",
+    "\n",
+    "    #-------Get VBM, CBM----------------\n",
+    "\n",
+    "    HOMO = -1000\n",
+    "    LUMO = 1000\n",
+    "    coor_k_point_HOMO = np.zeros((3)) #the coordinate of k point that stores HOMO\n",
+    "    coor_k_point_LUMO = np.zeros((3)) #the coordinate of k point that stores LUMO\n",
+    "    #band_gap_direct = 0.0\n",
+    "    band_gap_indirect = 0.0\n",
+    "    \n",
+    "    \n",
+    "    #band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+    "    #band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+    "    band_energy_max = 10\n",
+    "    band_energy_min = -10\n",
+    "    #N_band_energy_index = 10000\n",
+    "    #band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n",
+    "    #N_allowed_states = np.zeros(N_band_energy_index + 1)\n",
+    "    #i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n",
+    "\n",
+    "    for i_k_points_all in range(N_k_points_all):\n",
+    "        for i_bands in range(N_bands):\n",
+    "            #i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n",
+    "            #N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n",
+    "            band_energy = band_energies_all[i_bands][i_k_points_all]\n",
+    "            if(band_energy > 0):\n",
+    "                if(band_energy < LUMO):\n",
+    "                    LUMO = band_energy\n",
+    "            else:\n",
+    "                if(band_energy > HOMO):\n",
+    "                    HOMO = band_energy\n",
+    "    #for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n",
+    "    #    if(N_allowed_states[i_band_index] > 0):\n",
+    "    #        LUMO = band_energy_min + band_energy_step * i_band_index\n",
+    "    print('HOMO, LUMO: ',HOMO, LUMO)\n",
+    "    band_gap_indirect = abs(LUMO - HOMO)\n",
+    "    \n",
+    "    if(band_gap_indirect < 0.5): #VBM and CBM has to be found in another way for metals/charged system:\n",
+    "        HOMO = -1000\n",
+    "        LUMO = 1000\n",
+    "        band_energy_max = 10\n",
+    "        band_energy_min = 0\n",
+    "        N_band_energy_index = 10000\n",
+    "        band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n",
+    "        N_allowed_states = np.zeros(N_band_energy_index + 1)\n",
+    "        \n",
+    "        #get the DOS and store in N_allowed_states[]\n",
+    "        for i_k_points_all in range(N_k_points_all):\n",
+    "            for i_bands in range(N_bands):\n",
+    "                band_energy = band_energies_all[i_bands][i_k_points_all]\n",
+    "                if(band_energy_min < band_energy < band_energy_max):\n",
+    "                    i_band_index = math.floor((band_energy - band_energy_min) / band_energy_step)\n",
+    "                    N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1\n",
+    "        if_gapped = 0\n",
+    "        for i_band_index in range(N_band_energy_index): #go through the energy levels from the bottom\n",
+    "            band_energy = band_energy_min + band_energy_step * i_band_index\n",
+    "            if(N_allowed_states[i_band_index] == 0):\n",
+    "                if_gapped = if_gapped + 1\n",
+    "            if(band_energy > band_energy_max - 0.5) and (if_gapped == 0):\n",
+    "                print(\"No gap found in this system. It seems to be a metal.\")\n",
+    "                HOMO = 1000\n",
+    "                LUMO = 1000\n",
+    "                break\n",
+    "            #print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n",
+    "            \n",
+    "            if(N_allowed_states[i_band_index] > 0):\n",
+    "                if(if_gapped * band_energy_step> 0.3 ): #above VBM-CBM gap: LUMO\n",
+    "                    if(band_energy < LUMO):\n",
+    "                        #print(\"LUMO got!\")\n",
+    "                        LUMO = band_energy\n",
+    "                        break #break before touching another gap that is above the band gap\n",
+    "                if(if_gapped * band_energy_step < 0.3): #below VBM-CBM gap: HOMO\n",
+    "                    if(band_energy > HOMO):\n",
+    "                        #print(\"HOMO got!\")\n",
+    "                        HOMO = band_energy\n",
+    "                        \n",
+    "                if_gapped = 0\n",
+    "    \n",
+    "        print('HOMO, LUMO for metal/charged system: ',HOMO, LUMO)\n",
+    "    \n",
+    "    '''\n",
+    "\n",
+    "#    print('HOMO: ',tmp_HOMO_max)\n",
+    "    HOMO_global = tmp_HOMO_max\n",
+    "    LUMO_global = tmp_LUMO_min\n",
+    "    band_gap_indirect = LUMO_global - HOMO_global\n",
+    "    E_top_valence = HOMO_global\n",
+    "    if(band_gap_indirect < 0):\n",
+    "        band_gap_indirect = 0\n",
+    "\n",
+    "    #Rescal HOMO and LUMO with respect to HOMO\n",
+    "    HOMO_global = round((HOMO_global - E_top_valence), 3)\n",
+    "    LUMO_global = round((LUMO_global - E_top_valence), 3)\n",
+    "    '''\n",
+    "  \n",
+    "            \n",
+    "            \n",
+    "    #Find the position of HOMO, LUMO\n",
+    "\n",
+    "    for i_k_points in range(N_k_points_all):\n",
+    "        for i_bands in range(N_bands):\n",
+    "            if(abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001):\n",
+    "                coor_k_point_HOMO = k_coor_1D[i_k_points]\n",
+    "            if(abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001):\n",
+    "                coor_k_point_LUMO = k_coor_1D[i_k_points]  \n",
+    "\n",
+    "\n",
+    "               \n",
+    "                \n",
+    "    #Store the band data to band_obj\n",
+    "\n",
+    "    band_obj = {}\n",
+    "    band_obj[\"band_x_axis\"] = np.array(k_coor_1D).tolist()\n",
+    "    band_obj[\"band_y_axis\"] = np.array(band_energies_all).tolist()\n",
+    "    band_obj[\"labels\"] = np.array(label_obj).tolist()\n",
+    "    band_obj[\"HOMO_energy\"] = np.array(HOMO).tolist()\n",
+    "    band_obj[\"HOMO_coor\"] = np.array(coor_k_point_HOMO).tolist()\n",
+    "    band_obj[\"LUMO_energy\"] = np.array(LUMO).tolist()\n",
+    "    band_obj[\"LUMO_coor\"] = np.array(coor_k_point_LUMO).tolist()\n",
+    "    band_obj[\"average_N_k_points_per_inverse_distance\"] = np.array(average_N_k_points_per_inverse_distance).tolist()\n",
+    "    \n",
+    "\n",
+    "    \n",
+    "    return band_obj\n",
+    "\n",
+    "\n",
+    "#===============Get the space group information===========\n",
+    "def get_space_group(band_data):\n",
+    "    import pymatgen as mg\n",
+    "    from pymatgen.symmetry.analyzer import SpacegroupAnalyzer\n",
+    "\n",
+    "    simulation_cell = np.array(band_data[\"section_run\"][\"section_system\"][0].get('simulation_cell',\"empty\")) * 10000000000\n",
+    "    atom_positions = np.array(band_data[\"section_run\"][\"section_system\"][0].get('atom_positions',\"empty\")) * 10000000000\n",
+    "    atom_labels = np.array(band_data[\"section_run\"][\"section_system\"][0].get('atom_labels',\"empty\"))\n",
+    "    structure = mg.Structure(simulation_cell,atom_labels, atom_positions, coords_are_cartesian = True)\n",
+    "    \n",
+    "    finder = SpacegroupAnalyzer(structure, symprec=1e-3, angle_tolerance=5)\n",
+    "    space_group_symbol = finder.get_space_group_symbol()\n",
+    "    lattice_constant = []\n",
+    "    for item in structure.lattice.abc:\n",
+    "        lattice_constant.append(item)\n",
+    "    for i in range(len(lattice_constant)):\n",
+    "        item = str(round(lattice_constant[i], 3))\n",
+    "        lattice_constant[i] = item\n",
+    "    \n",
+    "    return [space_group_symbol, lattice_constant]\n",
+    "\n",
+    "#================Get the DOS data==============================\n",
+    "def get_dos_obj(dos_path):\n",
+    "    #dos_data: read from json file    \n",
+    "    #Load the data files for dos\n",
+    "    dos_data = load_jsonfile(dos_path)\n",
+    "\n",
+    "    print(dos_path)\n",
+    "    #N_dos_values = len(dos_data['sections']['section_run-0']['sections']['section_single_configuration_calculation-0']['section_dos'][0]['dos_energies'])\n",
+    "    N_dos_values = len(dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'])\n",
+    "    #in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n",
+    "\n",
+    "    dos_energies = np.zeros((N_dos_values))\n",
+    "    dos_energies_tmp = np.zeros((N_dos_values)) #tmp array for unit convertion\n",
+    "    dos_values = np.zeros((N_dos_values))\n",
+    "\n",
+    "    dos_energies_tmp = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies']\n",
+    "    dos_values =  dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_values'][0]\n",
+    "    \n",
+    "\n",
+    "    dos_fermi_energy= dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0].get('dos_fermi_energy',\"empty\")\n",
+    "    if(dos_fermi_energy == \"empty\"): #dos_fermi_energy is not available in EXCITING\n",
+    "        dos_fermi_energy_exciting = dos_data['section_run']['section_single_configuration_calculation'].get('x_exciting_dos_fermi',\"empty\")\n",
+    "        if(dos_fermi_energy_exciting == \"empty\"):\n",
+    "            dos_fermi_energy = 0\n",
+    "        else:\n",
+    "            dos_fermi_energy = dos_fermi_energy_exciting  / (1.60217656535 * pow(10,-19))\n",
+    "    else:\n",
+    "        dos_fermi_energy = dos_fermi_energy  / (1.60217656535 * pow(10,-19))\n",
+    "    print(\"dos_fermi_energy:\", dos_fermi_energy)\n",
+    "        \n",
+    "    for i_dos_values in range(N_dos_values):\n",
+    "        dos_energies[i_dos_values] = 0.0\n",
+    "        dos_energies[i_dos_values] = dos_energies_tmp[i_dos_values] / (1.60217656535 * pow(10,-19))\n",
+    "        dos_energies[i_dos_values] = round((dos_energies[i_dos_values] - dos_fermi_energy), 3) #reference with the fermi level\n",
+    "\n",
+    "    dos_obj = {}\n",
+    "    dos_obj[\"dos_x_axis\"] = np.array(dos_energies).tolist()\n",
+    "    dos_obj[\"dos_y_axis\"] = np.array(dos_values).tolist()\n",
+    "    dos_obj[\"dos_fermi_energy\"] = np.array(dos_fermi_energy).tolist()\n",
+    "\n",
+    "    return dos_obj\n",
+    "\n",
+    "\n",
+    "def get_info_obj(band_path):\n",
+    "\n",
+    "    #band_data: read from json file    \n",
+    "    #Load the data files for band\n",
+    "    band_data = load_jsonfile(band_path)\n",
+    "    info_obj = {}\n",
+    "    #---------Read the information of the calculation--------\n",
+    "    info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n",
+    "    info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n",
+    "    info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+    "    info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n",
+    "    \n",
+    "    #----------Get the space group information----------\n",
+    "    \n",
+    "    [space_group_symbol, lattice_constant] = get_space_group(band_data)\n",
+    "    info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist()\n",
+    "    info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist()\n",
+    "    print(\"space group:\", info_obj[\"space_group_symbol\"])\n",
+    "    print(\"lattice_constant:\", lattice_constant)\n",
+    "    \n",
+    "    return info_obj\n",
+    "\n",
+    "\n",
+    "#============main===========================================\n",
+    "\n",
+    "#import matplotlib.pyplot as plt\n",
+    "band_obj_all = []\n",
+    "dos_obj_all = []\n",
+    "info_obj_all = []\n",
+    "print(\"Number of materials: \", N_materials)\n",
+    "\n",
+    "for i in range (N_materials):\n",
+    "    print(\"Material: \", i)\n",
+    "    band_path = band_paths[i]\n",
+    "    dos_path = dos_paths[i]\n",
+    "    \n",
+    "    \n",
+    "    dos_obj = get_dos_obj(dos_path)\n",
+    "    dos_fermi_energy = dos_obj[\"dos_fermi_energy\"]\n",
+    "    band_obj = get_band_obj(band_path, dos_fermi_energy)\n",
+    "    info_obj = get_info_obj(band_path)\n",
+    "    \n",
+    "    band_obj_all.append(band_obj)\n",
+    "    dos_obj_all.append(dos_obj)\n",
+    "    info_obj_all.append(info_obj)\n",
+    "    \n",
+    "    \n",
+    "    print(\"average_N_k_points_per_inverse_distance: \", band_obj[\"average_N_k_points_per_inverse_distance\"])\n",
+    "\n",
+    "print(\"Finish processing data.\")\n",
+    "\n",
+    "#run_cell_by_tag('save_data_to_js')\n",
+    "\n",
+    "print(\"Initialization of visulization finished.\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 331,
+   "metadata": {
+    "tags": [
+     "js_plot"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "  \n",
+       "var N_max_show = 10; //Number of results to be shown by default\n",
+       "\n",
+       "\n",
+       "\n",
+       "\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "  \n",
+    "var N_max_show = 10; //Number of results to be shown by default\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%%javascript\n",
+    "// BACKUP!\n",
+    "/*\n",
+    "//Main plot function for given material:\n",
+    "    function plot_band_dos_i_backup(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n",
+    "    {\n",
+    "        //alert(\"plot_band_dos_i\")\n",
+    "        //i=0;\n",
+    "        lowerLim = -10\n",
+    "        upperLim = 10\n",
+    "        if_show_VBM = 0\n",
+    "        if_compare = 0\n",
+    "        i_in_compare_list = -1\n",
+    "        //i=0;\n",
+    "        var placeholder_band = \"#div_band\" + i.toString();\n",
+    "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+    "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+    "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+    "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+    "        var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "        var img_band_id = \"img_band\" + i.toString();\n",
+    "        var img_dos_id = \"img_dos\" + i.toString();\n",
+    "        var placeholder_band_compare = \"\";\n",
+    "\n",
+    "        if(i_in_compare_list == 1)\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_1\";\n",
+    "        }\n",
+    "        else if(i_in_compare_list == 2)\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_2\";\n",
+    "        }\n",
+    "        else\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n",
+    "        }\n",
+    "\n",
+    "        Object.size = function(obj) {\n",
+    "            var size = 0, key;\n",
+    "            for (key in obj) \n",
+    "            {\n",
+    "                if (obj.hasOwnProperty(key)) size++;\n",
+    "            }\n",
+    "            return size;\n",
+    "        };\n",
+    "\n",
+    "        //Get the number of bands\n",
+    "        //alert(\"Getting band\")\n",
+    "        //alert(band_obj_all)\n",
+    "        //alert(\"band_obj_all got!\")\n",
+    "        var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n",
+    "        var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n",
+    "        alert(band_obj_all[i][\"band_y_axis\"])\n",
+    "        band_plotdata = [];\n",
+    "\n",
+    "        for(var i_band =0; i_band < N_bands; i_band++)\n",
+    "        {\n",
+    "          var tmp_data = [];\n",
+    "          for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n",
+    "          {\n",
+    "            tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n",
+    "          }\n",
+    "          plotData = { shadowSize: 0 , data: tmp_data, color: 'black',  series: { lines: { show: true } , points: {show: false} } };\n",
+    "          band_plotdata.push(plotData);\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        var tmp_data0 = [[0, 0], [1, 0]];\n",
+    "        plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n",
+    "        band_plotdata.push(plotData0);\n",
+    "\n",
+    "        band_plotdata_overview = band_plotdata.slice(0);\n",
+    "\n",
+    "        var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n",
+    "        HOMOlabel = [\"VBM\"];\n",
+    "        plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false},  showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+    "\n",
+    "        var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n",
+    "        LUMOlabel = [\"CBM\"];\n",
+    "        plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false},  showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+    "\n",
+    "        //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "        if (if_show_VBM == 1)\n",
+    "        {\n",
+    "          band_plotdata.push(plotHOMO);\n",
+    "          band_plotdata.push(plotLUMO);\n",
+    "        }\n",
+    "\n",
+    " \n",
+    "        alert(img_band_id + band_plotdata)\n",
+    "            \n",
+    "        //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n",
+    "        //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\"  }\n",
+    "\n",
+    "        var canvas_band;\n",
+    "        var options_band = {\n",
+    "          canvas: true,\n",
+    "          //legend:{ type: \"canvas\" },\n",
+    "          series: { lines: { show: true, lineWidth: 2 }, \n",
+    "          points: { show: false } }, \n",
+    "          xaxis: { \n",
+    "            ticks: band_obj_all[i][\"labels\"], \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20}, \n",
+    "            zoomRange: false,\n",
+    "            panRange: false \n",
+    "          }, \n",
+    "          yaxis: { \n",
+    "            axisLabel: \"Energy (eV)\", \n",
+    "            axisLabelUseCanvas: true,\n",
+    "            //axisLabelUseCanvas: false,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial', \n",
+    "            axisLabelPadding: 10, \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20, family:\"Arial\"},\n",
+    "            tickLength:-5, \n",
+    "            min: lowerLim, \n",
+    "            max: upperLim,\n",
+    "            tickDecimals: 0, \n",
+    "            zoomRange: [0.001, 1000],\n",
+    "            panRange: [-100, 100] \n",
+    "          },\n",
+    "\n",
+    "          zoom: { \n",
+    "            interactive: true\n",
+    "          },\n",
+    "\n",
+    "          pan: {\n",
+    "            interactive: true\n",
+    "          }, \n",
+    "\n",
+    "          //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n",
+    "\n",
+    "          grid: { \n",
+    "            labelMargin: 15,\n",
+    "            hoverable: true, \n",
+    "            backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n",
+    "            borderWidth: {\n",
+    "              top: 2, \n",
+    "              right: 2,\n",
+    "              bottom: 2,\n",
+    "              left: 2,\n",
+    "              color : null } \n",
+    "          }\n",
+    "        }\n",
+    "        //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n",
+    "        //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n",
+    "        var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n",
+    "        image_band = plot_band.toDataURL();\n",
+    "        image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n",
+    "        //beakerx.image_band = image_band;\n",
+    "        document.getElementById(img_band_id).href= image_band;\n",
+    "        image_band_links[i] = image_band;\n",
+    "        alert(\"band plot done.\")\n",
+    "\n",
+    "\n",
+    "        //----Plot DOS----------------------\n",
+    "        var dos_plotdata = [];\n",
+    "        alert(\"dos:\"+dos_obj_all[i])\n",
+    "        var xdos = dos_obj_all[i][\"dos_x_axis\"];\n",
+    "        var ydos = dos_obj_all[i][\"dos_y_axis\"];\n",
+    "        var dosLabelPos = Math.max.apply(Math, ydos)/2;\n",
+    "        var d2 = [];\n",
+    "        for (var ii = 0; ii < xdos.length; ii+=1) {\n",
+    "          d2.push([ydos[ii],xdos[ii]]);\n",
+    "        }\n",
+    "        var plotData2={ shadowSize: 0, color: 'black' , data: d2}\n",
+    "        dos_plotdata.push(plotData2)\n",
+    "\n",
+    "        function find_xaxis_max_min(data, lowerbound, upperbound)\n",
+    "        {\n",
+    "                //data[xaxis,y] find the max and min value of x axis\n",
+    "                //alert(\"dos[0]:\" + data[0][\"data\"]);\n",
+    "                //alert(\"Bounds: \" + lowerbound + \" ,  \" + upperbound)\n",
+    "                var n_data = data.length;\n",
+    "                //alert(\"N dos: \" + n_data);\n",
+    "                var data_min = 1000000;\n",
+    "                var data_max = -1000000;\n",
+    "                var data_current = 0;\n",
+    "                for (var i = 0; i < n_data; i++)\n",
+    "                {\n",
+    "                    if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n",
+    "                    {\n",
+    "                        data_current = data[i][0];\n",
+    "                        //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n",
+    "                        if(data_current >= data_max)\n",
+    "                        {\n",
+    "                            data_max = data_current;\n",
+    "                        }\n",
+    "                        if(data_current <= data_min)\n",
+    "                        {\n",
+    "                            data_min = data_current;\n",
+    "                        }\n",
+    "                    }\n",
+    "                }\n",
+    "                var data_max_min = [data_max, data_min];\n",
+    "                //alert(\"data_max_min: \" + data_max_min);\n",
+    "                return data_max_min;\n",
+    "        }\n",
+    "        var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n",
+    "        var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n",
+    "\n",
+    "        var options_dos ={\n",
+    "          canvas: true,\n",
+    "          series: {\n",
+    "            lines: { show: true, lineWidth:2 },\n",
+    "            points: { show: false }\n",
+    "          },\n",
+    "\n",
+    "          yaxis: { \n",
+    "            axisLabel: \"\", \n",
+    "            axisLabelUseCanvas: true,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial', \n",
+    "            axisLabelPadding: 10, \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20},\n",
+    "            tickLength:-5, \n",
+    "            min: lowerLim, \n",
+    "            max: upperLim,\n",
+    "            tickDecimals: 0, \n",
+    "            zoomRange: [0.001, 1000],\n",
+    "            panRange: [-100, 100] \n",
+    "          },\n",
+    "\n",
+    "          xaxis: {\n",
+    "            axisLabel: \" \",\n",
+    "            axisLabelUseCanvas: false,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial',\n",
+    "            axisLabelPadding: 3,\n",
+    "            color:\"rgb(0, 0, 0)\",\n",
+    "            font: {size: 20, family:\"Arial\"},\n",
+    "            //ticks: 10,\n",
+    "            tickLength:0,\n",
+    "            min: dos_x_max_min[1],//0,\n",
+    "            max: dos_x_max_min[0],//1,\n",
+    "            tickDecimals: 0,\n",
+    "            ticks: [[ dosLabelPos ,'DOS']],\n",
+    "            //tickFormatter: MyFormatter\n",
+    "            panRange: false\n",
+    "          },\n",
+    "          pan: {\n",
+    "            interactive: true\n",
+    "          }, \n",
+    "\n",
+    "          grid: {\n",
+    "            labelMargin: 15,\n",
+    "            hoverable: true,\n",
+    "            //borderWidth : 1000,\n",
+    "            //show : false,\n",
+    "            //  //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n",
+    "            backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n",
+    "            borderWidth: {\n",
+    "              top: 2,\n",
+    "              right: 2,\n",
+    "              bottom: 2,\n",
+    "              left: 2,\n",
+    "              color : null\n",
+    "            }\n",
+    "          }\n",
+    "        }\n",
+    "        var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n",
+    "        var image_dos = plot_dos.toDataURL();\n",
+    "        image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n",
+    "        image_dos = image_dos;\n",
+    "        document.getElementById(img_dos_id).href= image_dos;\n",
+    "        \n",
+    "    }\n",
+    "*/"
+   ]
+  }
+ ],
+ "metadata": {
+  "celltoolbar": "Tags",
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.6.7"
+  },
+  "toc": {
+   "base_numbering": 1,
+   "nav_menu": {},
+   "number_sections": false,
+   "sideBar": false,
+   "skip_h1_title": false,
+   "title_cell": "Table of Contents",
+   "title_sidebar": "Contents",
+   "toc_cell": false,
+   "toc_position": {},
+   "toc_section_display": false,
+   "toc_window_display": false
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/Nomad_tutorial_head.png b/Nomad_tutorial_head.png
new file mode 100644
index 0000000000000000000000000000000000000000..c31c475de3e3e8df2e858a511b924b65d14a32ee
Binary files /dev/null and b/Nomad_tutorial_head.png differ
diff --git a/band_structure_visualization.ipynb b/band_structure_visualization.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..b2c4549632725c1ee3c50a465af06e961f44b6c1
--- /dev/null
+++ b/band_structure_visualization.ipynb
@@ -0,0 +1,4968 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "init_cell": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<style>.container { width:100% !important; }</style>"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "from IPython.core.display import display, HTML\n",
+    "display(HTML(\"<style>.container { width:100% !important; }</style>\"))\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "init_cell": true
+   },
+   "outputs": [],
+   "source": [
+    "from IPython.core.display import Javascript\n",
+    "from IPython.display import display\n",
+    "\n",
+    "def run_cell_by_tag(tags):\n",
+    "    display(Javascript(\"window.runCells('\"+tags+\"')\"))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "init_cell": true,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "    code_show=true; \n",
+       "    function code_toggle() {\n",
+       "        if (code_show)\n",
+       "        {\n",
+       "            $('div.input').hide();\n",
+       "        } \n",
+       "        else \n",
+       "        {\n",
+       "            $('div.input').show();\n",
+       "        }\n",
+       "        code_show = !code_show\n",
+       "    } \n",
+       "    $( document ).ready(code_toggle);\n",
+       "</script>\n",
+       "The raw code for this notebook is by default hidden for easier reading.\n",
+       "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>.\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "    code_show=true; \n",
+    "    function code_toggle() {\n",
+    "        if (code_show)\n",
+    "        {\n",
+    "            $('div.input').hide();\n",
+    "        } \n",
+    "        else \n",
+    "        {\n",
+    "            $('div.input').show();\n",
+    "        }\n",
+    "        code_show = !code_show\n",
+    "    } \n",
+    "    $( document ).ready(code_toggle);\n",
+    "</script>\n",
+    "The raw code for this notebook is by default hidden for easier reading.\n",
+    "To toggle on/off the raw code, click <a href=\"javascript:code_toggle()\">here</a>."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "init_cell": true,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "\n",
+       "\n",
+       "<div align=\"left\" style=\"background-color: rgba(149,170,79, 1.0); width: 100%; height: 390px; overflow: hidden;\">\n",
+       "    <div >\n",
+       "        <table>\n",
+       "            <tr></tr>\n",
+       "            <tr>\n",
+       "                <td><img src=\"Nomad_tutorial_head.png\"></td>\n",
+       "            </tr>\n",
+       "        </table>\n",
+       "    </div>\n",
+       "\n",
+       "    <br><br>\n",
+       "    <div style=\"position:relative; left:3%\"><font size=6em  color=\"#20335d\" ><b> -  Visualization of the band structure of materials </b></font></div>\n",
+       "    <p style=\"position:relative;left:10%; \">\n",
+       "        <br>\n",
+       "        Created by:\n",
+       "\n",
+       "        Xiangyue Liu<sup>1</sup>(<a href=\"mailto:xyliu@fhi-berlin.mpg.de\">email</a>),\n",
+       "        \n",
+       "        Fawzi Mohamed<sup>1</sup>,\n",
+       "        \n",
+       "        and Luca M. Ghiringhelli<sup>1</sup>(<a href=\"mailto:ghiringhelli@fhi-berlin.mpg.de\">email</a>), <br>\n",
+       "\n",
+       "        <br><br>\n",
+       "        <sup>1</sup> Fritz Haber Institute of the Max Planck Society, Faradayweg 4-6, D-14195 Berlin, Germany <br>\n",
+       "        <br>\n",
+       "\n",
+       "\n",
+       "    </p>\n",
+       "    <br>\n",
+       "    <div style=\"position:relative;bottom:3%\">\n",
+       "        <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#999999\" size=\"10em\">v2.0.0</font></div>\n",
+       "        <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#666666\" size=\"2.7em\">[Last updated: August 5, 2019]</font></div>\n",
+       "    </div>\n",
+       "\n",
+       "</div>\n",
+       "\n",
+       "\n",
+       "<div style='text-align: right;'>\n",
+       "    <a href=\"https://analytics-toolkit.nomad-coe.eu/home/\" class=\"btn btn-primary\" style=\"font-size:larger;\">Back to Analytics Home</a> \n",
+       "    <a href=\"https://www.nomad-coe.eu/\" class=\"btn btn-primary\" style=\"font-size:larger; \">Back to nomad-coe</a> \n",
+       "</div>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "\n",
+    "\n",
+    "<div align=\"left\" style=\"background-color: rgba(149,170,79, 1.0); width: 100%; height: 390px; overflow: hidden;\">\n",
+    "    <div >\n",
+    "        <table>\n",
+    "            <tr></tr>\n",
+    "            <tr>\n",
+    "                <td><img src=\"Nomad_tutorial_head.png\"></td>\n",
+    "            </tr>\n",
+    "        </table>\n",
+    "    </div>\n",
+    "\n",
+    "    <br><br>\n",
+    "    <div style=\"position:relative; left:3%\"><font size=6em  color=\"#20335d\" ><b> -  Visualization of the band structure of materials </b></font></div>\n",
+    "    <p style=\"position:relative;left:10%; \">\n",
+    "        <br>\n",
+    "        Created by:\n",
+    "\n",
+    "        Xiangyue Liu<sup>1</sup>(<a href=\"mailto:xyliu@fhi-berlin.mpg.de\">email</a>),\n",
+    "        \n",
+    "        Fawzi Mohamed<sup>1</sup>,\n",
+    "        \n",
+    "        and Luca M. Ghiringhelli<sup>1</sup>(<a href=\"mailto:ghiringhelli@fhi-berlin.mpg.de\">email</a>), <br>\n",
+    "\n",
+    "        <br><br>\n",
+    "        <sup>1</sup> Fritz Haber Institute of the Max Planck Society, Faradayweg 4-6, D-14195 Berlin, Germany <br>\n",
+    "        <br>\n",
+    "\n",
+    "\n",
+    "    </p>\n",
+    "    <br>\n",
+    "    <div style=\"position:relative;bottom:3%\">\n",
+    "        <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#999999\" size=\"10em\">v2.0.0</font></div>\n",
+    "        <div style=\"position:absolute;right:5%;bottom: 0%;\"><font color=\"#666666\" size=\"2.7em\">[Last updated: August 5, 2019]</font></div>\n",
+    "    </div>\n",
+    "\n",
+    "</div>\n",
+    "\n",
+    "\n",
+    "<div style='text-align: right;'>\n",
+    "    <a href=\"https://analytics-toolkit.nomad-coe.eu/home/\" class=\"btn btn-primary\" style=\"font-size:larger;\">Back to Analytics Home</a> \n",
+    "    <a href=\"https://www.nomad-coe.eu/\" class=\"btn btn-primary\" style=\"font-size:larger; \">Back to nomad-coe</a> \n",
+    "</div>\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "init_cell": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "    window.findCellIndicesByTag = function findCellIndicesByTag(tagName) {\n",
+       "      return (Jupyter.notebook.get_cells()\n",
+       "        .filter(\n",
+       "          ({metadata: {tags}}) => tags && tags.includes(tagName)\n",
+       "        )\n",
+       "        .map((cell) => Jupyter.notebook.find_cell_index(cell))\n",
+       "      );\n",
+       "    };\n",
+       "\n",
+       "\n",
+       "    window.runCells = function runPlotCells(tags) {\n",
+       "        var c = window.findCellIndicesByTag(tags);\n",
+       "        Jupyter.notebook.execute_cells(c);\n",
+       "    };\n",
+       "</script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "    window.findCellIndicesByTag = function findCellIndicesByTag(tagName) {\n",
+    "      return (Jupyter.notebook.get_cells()\n",
+    "        .filter(\n",
+    "          ({metadata: {tags}}) => tags && tags.includes(tagName)\n",
+    "        )\n",
+    "        .map((cell) => Jupyter.notebook.find_cell_index(cell))\n",
+    "      );\n",
+    "    };\n",
+    "\n",
+    "\n",
+    "    window.runCells = function runPlotCells(tags) {\n",
+    "        var c = window.findCellIndicesByTag(tags);\n",
+    "        Jupyter.notebook.execute_cells(c);\n",
+    "    };\n",
+    "</script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 53,
+   "metadata": {
+    "init_cell": true,
+    "tags": [
+     "search_materials"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<br><br>\n",
+       "\n",
+       "<p style=\"color: #20335d;font-weight: 450; font-size: 14pt;font-family: Arial;\"> This tutorial visulizes the band structures and density of states (DOS) of the NOMAD materials.</p>\n",
+       "<br><br>\n",
+       "\n",
+       "<style>\n",
+       ".button {\n",
+       "    background-color: #e7e7e7;\n",
+       "    border: 0.5px solid #A4A4A4;\n",
+       "    color: black;\n",
+       "    padding: 15px 32px;\n",
+       "    text-align: center;\n",
+       "    text-decoration: none;\n",
+       "    display: inline-block;\n",
+       "    font-family: Arial;\n",
+       "    font-size: 16px;\n",
+       "    margin: 4px 2px;\n",
+       "    cursor: pointer;\n",
+       "}\n",
+       "\n",
+       "  .text-normal-black{\n",
+       "    color: #000;font-weight: 200; font-size: 10pt;\n",
+       "    font-family: Arial;\n",
+       "  }\n",
+       "  .div_band_dos{\n",
+       "    box-sizing: border-box;\n",
+       "    width: 100%;\n",
+       "    height: 600px;\n",
+       "    font-weight: 100;\n",
+       "    font-family: Arial;\n",
+       "    padding-left: 20px;\n",
+       "    padding-top: 10px;\n",
+       "    padding-right: 1em;\n",
+       "    margin: 0;\n",
+       "    border: 0;\n",
+       "  }\n",
+       "  .div_band_dos_compare{\n",
+       "    box-sizing: border-box;\n",
+       "    width: 1600px;\n",
+       "    height: 600px;\n",
+       "    color: #00AEFF;\n",
+       "    font-weight: 100;\n",
+       "    font-family: Arial;\n",
+       "    padding-left: 20px;\n",
+       "    padding-top: 10px;\n",
+       "    padding-right: 1em;\n",
+       "    margin: 0;\n",
+       "    border: 0;\n",
+       "  }\n",
+       "  .div_band{\n",
+       "    font-family: Arial;\n",
+       "    font-size: 0.875em;\n",
+       "    width: 37%;\n",
+       "    height: 80%;\n",
+       "    background-color: #fff;\n",
+       "    float:left;\n",
+       "  }\n",
+       "  .div_dos{\n",
+       "    font-family: Arial;\n",
+       "    font-size: 0.875em;\n",
+       "    width: 13%;\n",
+       "    height: 80%;\n",
+       "    background-color: #fff;\n",
+       "    float:left;\n",
+       "  }\n",
+       "  .div_tools{\n",
+       "    color: #20335d;font-weight: 150; font-size: 13pt;\n",
+       "    width: 35%;\n",
+       "    height: 80%;\n",
+       "    background-color: #fff;\n",
+       "    margin-left:20pt;\n",
+       "    float:left;\n",
+       "    font-family: Arial;\n",
+       "\n",
+       "  }\n",
+       "  .div_checkbox_compare{\n",
+       "    color: #888;font-weight: 150; font-size: 12pt;\n",
+       "    width: 10%;\n",
+       "    height: 80%;\n",
+       "    background-color: #fff;\n",
+       "    border: solid #fff 1px;\n",
+       "    float:right;\n",
+       "    font-family: Arial;\n",
+       "\n",
+       "  }\n",
+       "  .div_overview{\n",
+       "    width: 300px;\n",
+       "    height: 200px;\n",
+       "    background-color: #fff;\n",
+       "    margin-left:10px; \n",
+       "    margin-top: 20px;\n",
+       "    font-family: Arial;\n",
+       "\n",
+       "  }\n",
+       "  .button_tools {\n",
+       "    background-color: #F0F0F0;\n",
+       "    border: 0.5px solid #A4A4A4;\n",
+       "    color: black;\n",
+       "    padding: 10px 15px;\n",
+       "    text-align: center;\n",
+       "    text-decoration: none;\n",
+       "    display: inline-block;\n",
+       "    font-size: 16px;\n",
+       "    margin: 4px 2px;\n",
+       "    cursor: pointer;\n",
+       "    font-family: Arial;\n",
+       "\n",
+       "  }\n",
+       "\n",
+       "  \n",
+       "  .g-before-after{position:relative;overflow:hidden;width:500px}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%}\n",
+       "</style>\n",
+       "\n",
+       "<script>\n",
+       "    //Search for certain keyword: https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\n",
+       "    //FjiYy5-ETRCrs5ktzJA55w/bOY0cPkBvvNAY7pZdbginlKXJ2kF\n",
+       "    //\"upload_id\"/\"calc_id\"\n",
+       "    \n",
+       "    //Global variables\n",
+       "    var paths_section_k_band_segment = []; \n",
+       "    var paths_section_dos = [];\n",
+       "    var band_obj_all = [];\n",
+       "    var dos_obj_all = [];\n",
+       "    var info_obj_all = [];\n",
+       "    \n",
+       "    var band_paths = [];\n",
+       "    var dos_paths = [];\n",
+       "    var N_materials = 0;  //Number of materials that have both band and DOS in the same calculation   \n",
+       "    \n",
+       "    \n",
+       "    function getJSON(url) {\n",
+       "        var resp ;\n",
+       "        var xmlHttp ;\n",
+       "\n",
+       "        resp  = '' ;\n",
+       "        xmlHttp = new XMLHttpRequest();\n",
+       "\n",
+       "        if(xmlHttp != null)\n",
+       "        {\n",
+       "            xmlHttp.open( \"GET\", url, false );\n",
+       "            xmlHttp.send( null );\n",
+       "            resp = xmlHttp.responseText;\n",
+       "        }\n",
+       "\n",
+       "        return resp;\n",
+       "    }\n",
+       "    function match_band_dos()\n",
+       "    {\n",
+       "        //TMP for local tests\n",
+       "        /*\n",
+       "        paths_section_k_band_segment = [\"data/kOJR-AlPSgiNG9AdZoxd4g_9mxjIU0edrPosfsTc4uyDG9H_UXr.json\",\"data/kOJR-AlPSgiNG9AdZoxd4g_lfkGCmWozYENeiGhu5W7dJUqLTkj.json\"];\n",
+       "        paths_section_dos = [\"data/kOJR-AlPSgiNG9AdZoxd4g_8tEGnaz0yY91eSyysKZkIUH9qx8J.json\", \"data/kOJR-AlPSgiNG9AdZoxd4g_lxUT3viRZcC_1IsH_KvO5tChAtV1.json\"];\n",
+       "        */\n",
+       "\n",
+       "        //band_paths = [];\n",
+       "        //dos_paths = [];\n",
+       "        //N_materials = 0;    \n",
+       "        \n",
+       "        var data_k_band = [];\n",
+       "        for(var i_path_k_band = 0; i_path_k_band < paths_section_k_band_segment.length; i_path_k_band ++)\n",
+       "        {\n",
+       "            var i_data_k_band_json = JSON.parse(getJSON(paths_section_k_band_segment[i_path_k_band]));\n",
+       "            var i_data_k_band = {};\n",
+       "            i_data_k_band[\"program_name\"] = i_data_k_band_json[\"section_run\"][\"program_name\"];\n",
+       "            i_data_k_band[\"k_mesh_points\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n",
+       "            i_data_k_band[\"simulation_cell\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n",
+       "            i_data_k_band[\"atom_positions\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n",
+       "            i_data_k_band[\"atom_labels\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+       "            i_data_k_band[\"XC_functional_name\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n",
+       "            i_data_k_band[\"path\"] = paths_section_k_band_segment[i_path_k_band];\n",
+       "            data_k_band.push(i_data_k_band);\n",
+       "        }\n",
+       "\n",
+       "        var data_dos = [];\n",
+       "        for(var i_path_dos = 0; i_path_dos < paths_section_dos.length; i_path_dos ++)\n",
+       "        {\n",
+       "            var i_data_dos_json = JSON.parse(getJSON(paths_section_dos[i_path_dos]));\n",
+       "            var i_data_dos = {};\n",
+       "            i_data_dos[\"program_name\"] = i_data_dos_json[\"section_run\"][\"program_name\"];\n",
+       "            i_data_dos[\"k_mesh_points\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n",
+       "            i_data_dos[\"simulation_cell\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n",
+       "            i_data_dos[\"atom_positions\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n",
+       "            i_data_dos[\"atom_labels\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+       "            i_data_dos[\"XC_functional_name\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n",
+       "            i_data_dos[\"path\"] = paths_section_dos[i_path_dos];\n",
+       "            data_dos.push(i_data_dos);       \n",
+       "        }\n",
+       "\n",
+       "        //Matching: band[i] ~ dos[i]  (the same systems are arranged with the same index)\n",
+       "        band_paths = [];\n",
+       "        dos_paths = [];\n",
+       "        N_materials = 0;\n",
+       "        for(var i_k_band = 0; i_k_band < data_k_band.length; i_k_band ++)\n",
+       "        {\n",
+       "            for(var i_dos = 0; i_dos < data_dos.length; i_dos ++)\n",
+       "            {\n",
+       "                if(data_k_band[i_k_band][\"program_name\"] != data_dos[i_dos][\"program_name\"])\n",
+       "                    continue;        \n",
+       "                //if(data_k_band[i_k_band][\"k_mesh_points\"].join() != data_dos[i_dos][\"k_mesh_points\"].join())\n",
+       "                //   continue;\n",
+       "                if(data_k_band[i_k_band][\"simulation_cell\"].join() != data_dos[i_dos][\"simulation_cell\"].join())\n",
+       "                    continue;\n",
+       "                if(data_k_band[i_k_band][\"atom_positions\"].join() != data_dos[i_dos][\"atom_positions\"].join())\n",
+       "                    continue;\n",
+       "                if(data_k_band[i_k_band][\"atom_labels\"].join() != data_dos[i_dos][\"atom_labels\"].join())\n",
+       "                    continue;\n",
+       "                if(data_k_band[i_k_band][\"XC_functional_name\"] != data_dos[i_dos][\"XC_functional_name\"])\n",
+       "                    continue;\n",
+       "                band_paths.push(data_k_band[i_k_band][\"path\"]);\n",
+       "                dos_paths.push(data_dos[i_dos][\"path\"]);\n",
+       "                N_materials ++;\n",
+       "            }\n",
+       "        }\n",
+       "        //Pass the arrays to python\n",
+       "\n",
+       "        var command = \"N_materials = \" + N_materials + \";\"\n",
+       "        var kernel = IPython.notebook.kernel;\n",
+       "        command += \"band_paths = \" + \"[\\'\" + band_paths.join(\"\\',\\'\") + \"\\'];\";\n",
+       "        command += \"dos_paths = \" + \"[\\'\" + dos_paths.join(\"\\',\\'\") + \"\\'];\";\n",
+       "        kernel.execute(command);\n",
+       "        \n",
+       "        \n",
+       "    }\n",
+       "\n",
+       "    function get_paths_from_search_results(result_json, div_id_search_results,div_head)\n",
+       "    {\n",
+       "        paths = [];\n",
+       "        search_results_content = [div_head, '<table>', '<tr><th>Chemical formula</th><th>Spacegroup</th><th>Code</th><th>XC functional</th><th>Upload ID</th><th>Calculation ID</th><th>URL</th></tr>'];\n",
+       "        for(var i_key in result_json)\n",
+       "        {\n",
+       "            if(i_key == \"results\")\n",
+       "            {\n",
+       "                for(var system in result_json[i_key])\n",
+       "                {\n",
+       "                    //Get the path to the data files (json): https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/upload_id/calc_id \n",
+       "                    path = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/\" + result_json[i_key][system][\"upload_id\"] + \"/\" + result_json[i_key][system][\"calc_id\"]\n",
+       "                    paths.push(path);\n",
+       "                    \n",
+       "                    //Show the results in div\n",
+       "                    // \"formula\" \"spacegroup_symbol\" \"code_name\" \"xc_functional\"\n",
+       "                    content = '<tr>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"formula\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"spacegroup_symbol\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"code_name\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"xc_functional\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"upload_id\"] + '</td>';\n",
+       "                    content += '<td>' + result_json[i_key][system][\"calc_id\"] + '</td>';                    \n",
+       "                    content += '<td>' + path + '</td>';\n",
+       "                    content += '</tr>';\n",
+       "                    search_results_content.push(content);\n",
+       "                }\n",
+       "            }\n",
+       "        }\n",
+       "        search_results_content.push('</table>');\n",
+       "        document.getElementById(div_id_search_results).innerHTML = search_results_content.join('');\n",
+       "        return paths\n",
+       "    }\n",
+       "    \n",
+       "    \n",
+       "    \n",
+       "\n",
+       "    \n",
+       "    \n",
+       "    \n",
+       "    function submit_search()\n",
+       "    {\n",
+       "        \n",
+       "        var result;\n",
+       "        var formula = document.getElementById(\"keyword_chemical_formula\").value;\n",
+       "        var query_command_k_band = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_k_band_segment\";\n",
+       "        var query_command_dos =  \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_dos\";\n",
+       "        //result = getJSON(\"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\");\n",
+       "        var result_k_band = getJSON(query_command_k_band);\n",
+       "        var result_dos = getJSON(query_command_dos);\n",
+       "        var result_json_k_band = JSON.parse(result_k_band);//parse the searching results to json from URL\n",
+       "        var result_json_dos = JSON.parse(result_dos);\n",
+       "        paths_section_k_band_segment = []; \n",
+       "        paths_section_dos = [];\n",
+       "        paths_section_k_band_segment = get_paths_from_search_results(result_json_k_band, \"search_results_section_k_band_segment\", \"<br><br><font size=4em>Calculations containing band structures:</font><br>\");\n",
+       "        paths_section_dos = get_paths_from_search_results(result_json_dos, \"search_results_section_dos\", \"<br><font size=4em>Calculations containing DOS:</font><br>\");\n",
+       "     \n",
+       "        var promise = Promise.resolve();\n",
+       "        promise\n",
+       "            .then(match_band_dos())\n",
+       "            .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')))\n",
+       "            .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')));\n",
+       "        \n",
+       "        //match_band_dos();\n",
+       "              \n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')); //Read the json files, and prepare data for plot\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')); //Prepare for plot\n",
+       "    }\n",
+       "    function reset_search()\n",
+       "    {\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('search_materials'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot'));\n",
+       "    }\n",
+       "    \n",
+       "    \n",
+       "</script>\n",
+       "<font size=4em>Please input the chemical formula:</font>\n",
+       "<input type=\"text\" id=\"keyword_chemical_formula\" value=\"AlInO3\"> \n",
+       "<button class=\"button\" onclick=\"submit_search()\">Search</button>\n",
+       "<button class=\"button\" onclick=\"reset_search()\">Reset</button>\n",
+       "<br><br><br>\n",
+       "<div id=\"search_results_section_k_band_segment\"></div>\n",
+       "<div id=\"search_results_section_dos\"></div>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%html\n",
+    "<br><br>\n",
+    "\n",
+    "<p style=\"color: #20335d;font-weight: 450; font-size: 14pt;font-family: Arial;\"> This tutorial visulizes the band structures and density of states (DOS) of the NOMAD materials.</p>\n",
+    "<br><br>\n",
+    "\n",
+    "<style>\n",
+    ".button {\n",
+    "    background-color: #e7e7e7;\n",
+    "    border: 0.5px solid #A4A4A4;\n",
+    "    color: black;\n",
+    "    padding: 15px 32px;\n",
+    "    text-align: center;\n",
+    "    text-decoration: none;\n",
+    "    display: inline-block;\n",
+    "    font-family: Arial;\n",
+    "    font-size: 16px;\n",
+    "    margin: 4px 2px;\n",
+    "    cursor: pointer;\n",
+    "}\n",
+    "\n",
+    "  .text-normal-black{\n",
+    "    color: #000;font-weight: 200; font-size: 10pt;\n",
+    "    font-family: Arial;\n",
+    "  }\n",
+    "  .div_band_dos{\n",
+    "    box-sizing: border-box;\n",
+    "    width: 100%;\n",
+    "    height: 600px;\n",
+    "    font-weight: 100;\n",
+    "    font-family: Arial;\n",
+    "    padding-left: 20px;\n",
+    "    padding-top: 10px;\n",
+    "    padding-right: 1em;\n",
+    "    margin: 0;\n",
+    "    border: 0;\n",
+    "  }\n",
+    "  .div_band_dos_compare{\n",
+    "    box-sizing: border-box;\n",
+    "    width: 1600px;\n",
+    "    height: 600px;\n",
+    "    color: #00AEFF;\n",
+    "    font-weight: 100;\n",
+    "    font-family: Arial;\n",
+    "    padding-left: 20px;\n",
+    "    padding-top: 10px;\n",
+    "    padding-right: 1em;\n",
+    "    margin: 0;\n",
+    "    border: 0;\n",
+    "  }\n",
+    "  .div_band{\n",
+    "    font-family: Arial;\n",
+    "    font-size: 0.875em;\n",
+    "    width: 37%;\n",
+    "    height: 80%;\n",
+    "    background-color: #fff;\n",
+    "    float:left;\n",
+    "  }\n",
+    "  .div_dos{\n",
+    "    font-family: Arial;\n",
+    "    font-size: 0.875em;\n",
+    "    width: 13%;\n",
+    "    height: 80%;\n",
+    "    background-color: #fff;\n",
+    "    float:left;\n",
+    "  }\n",
+    "  .div_tools{\n",
+    "    color: #20335d;font-weight: 150; font-size: 13pt;\n",
+    "    width: 35%;\n",
+    "    height: 80%;\n",
+    "    background-color: #fff;\n",
+    "    margin-left:20pt;\n",
+    "    float:left;\n",
+    "    font-family: Arial;\n",
+    "\n",
+    "  }\n",
+    "  .div_checkbox_compare{\n",
+    "    color: #888;font-weight: 150; font-size: 12pt;\n",
+    "    width: 10%;\n",
+    "    height: 80%;\n",
+    "    background-color: #fff;\n",
+    "    border: solid #fff 1px;\n",
+    "    float:right;\n",
+    "    font-family: Arial;\n",
+    "\n",
+    "  }\n",
+    "  .div_overview{\n",
+    "    width: 300px;\n",
+    "    height: 200px;\n",
+    "    background-color: #fff;\n",
+    "    margin-left:10px; \n",
+    "    margin-top: 20px;\n",
+    "    font-family: Arial;\n",
+    "\n",
+    "  }\n",
+    "  .button_tools {\n",
+    "    background-color: #F0F0F0;\n",
+    "    border: 0.5px solid #A4A4A4;\n",
+    "    color: black;\n",
+    "    padding: 10px 15px;\n",
+    "    text-align: center;\n",
+    "    text-decoration: none;\n",
+    "    display: inline-block;\n",
+    "    font-size: 16px;\n",
+    "    margin: 4px 2px;\n",
+    "    cursor: pointer;\n",
+    "    font-family: Arial;\n",
+    "\n",
+    "  }\n",
+    "\n",
+    "  \n",
+    "  .g-before-after{position:relative;overflow:hidden;width:500px}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%}\n",
+    "</style>\n",
+    "\n",
+    "<script>\n",
+    "    //Search for certain keyword: https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\n",
+    "    //FjiYy5-ETRCrs5ktzJA55w/bOY0cPkBvvNAY7pZdbginlKXJ2kF\n",
+    "    //\"upload_id\"/\"calc_id\"\n",
+    "    \n",
+    "    //Global variables\n",
+    "    var paths_section_k_band_segment = []; \n",
+    "    var paths_section_dos = [];\n",
+    "    var band_obj_all = [];\n",
+    "    var dos_obj_all = [];\n",
+    "    var info_obj_all = [];\n",
+    "    \n",
+    "    var band_paths = [];\n",
+    "    var dos_paths = [];\n",
+    "    var N_materials = 0;  //Number of materials that have both band and DOS in the same calculation   \n",
+    "    \n",
+    "    \n",
+    "    function getJSON(url) {\n",
+    "        var resp ;\n",
+    "        var xmlHttp ;\n",
+    "\n",
+    "        resp  = '' ;\n",
+    "        xmlHttp = new XMLHttpRequest();\n",
+    "\n",
+    "        if(xmlHttp != null)\n",
+    "        {\n",
+    "            xmlHttp.open( \"GET\", url, false );\n",
+    "            xmlHttp.send( null );\n",
+    "            resp = xmlHttp.responseText;\n",
+    "        }\n",
+    "\n",
+    "        return resp;\n",
+    "    }\n",
+    "    function match_band_dos()\n",
+    "    {\n",
+    "        //TMP for local tests\n",
+    "        /*\n",
+    "        paths_section_k_band_segment = [\"data/kOJR-AlPSgiNG9AdZoxd4g_9mxjIU0edrPosfsTc4uyDG9H_UXr.json\",\"data/kOJR-AlPSgiNG9AdZoxd4g_lfkGCmWozYENeiGhu5W7dJUqLTkj.json\"];\n",
+    "        paths_section_dos = [\"data/kOJR-AlPSgiNG9AdZoxd4g_8tEGnaz0yY91eSyysKZkIUH9qx8J.json\", \"data/kOJR-AlPSgiNG9AdZoxd4g_lxUT3viRZcC_1IsH_KvO5tChAtV1.json\"];\n",
+    "        */\n",
+    "\n",
+    "        //band_paths = [];\n",
+    "        //dos_paths = [];\n",
+    "        //N_materials = 0;    \n",
+    "        \n",
+    "        var data_k_band = [];\n",
+    "        for(var i_path_k_band = 0; i_path_k_band < paths_section_k_band_segment.length; i_path_k_band ++)\n",
+    "        {\n",
+    "            var i_data_k_band_json = JSON.parse(getJSON(paths_section_k_band_segment[i_path_k_band]));\n",
+    "            var i_data_k_band = {};\n",
+    "            i_data_k_band[\"program_name\"] = i_data_k_band_json[\"section_run\"][\"program_name\"];\n",
+    "            i_data_k_band[\"k_mesh_points\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n",
+    "            i_data_k_band[\"simulation_cell\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n",
+    "            i_data_k_band[\"atom_positions\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n",
+    "            i_data_k_band[\"atom_labels\"] = i_data_k_band_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+    "            i_data_k_band[\"XC_functional_name\"] = i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_k_band_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n",
+    "            i_data_k_band[\"path\"] = paths_section_k_band_segment[i_path_k_band];\n",
+    "            data_k_band.push(i_data_k_band);\n",
+    "        }\n",
+    "\n",
+    "        var data_dos = [];\n",
+    "        for(var i_path_dos = 0; i_path_dos < paths_section_dos.length; i_path_dos ++)\n",
+    "        {\n",
+    "            var i_data_dos_json = JSON.parse(getJSON(paths_section_dos[i_path_dos]));\n",
+    "            var i_data_dos = {};\n",
+    "            i_data_dos[\"program_name\"] = i_data_dos_json[\"section_run\"][\"program_name\"];\n",
+    "            i_data_dos[\"k_mesh_points\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"k_mesh_points\"];\n",
+    "            i_data_dos[\"simulation_cell\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"simulation_cell\"];\n",
+    "            i_data_dos[\"atom_positions\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_positions\"];\n",
+    "            i_data_dos[\"atom_labels\"] = i_data_dos_json[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+    "            i_data_dos[\"XC_functional_name\"] = i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \"-\" + i_data_dos_json[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"]\n",
+    "            i_data_dos[\"path\"] = paths_section_dos[i_path_dos];\n",
+    "            data_dos.push(i_data_dos);       \n",
+    "        }\n",
+    "\n",
+    "        //Matching: band[i] ~ dos[i]  (the same systems are arranged with the same index)\n",
+    "        band_paths = [];\n",
+    "        dos_paths = [];\n",
+    "        N_materials = 0;\n",
+    "        for(var i_k_band = 0; i_k_band < data_k_band.length; i_k_band ++)\n",
+    "        {\n",
+    "            for(var i_dos = 0; i_dos < data_dos.length; i_dos ++)\n",
+    "            {\n",
+    "                if(data_k_band[i_k_band][\"program_name\"] != data_dos[i_dos][\"program_name\"])\n",
+    "                    continue;        \n",
+    "                //if(data_k_band[i_k_band][\"k_mesh_points\"].join() != data_dos[i_dos][\"k_mesh_points\"].join())\n",
+    "                //   continue;\n",
+    "                if(data_k_band[i_k_band][\"simulation_cell\"].join() != data_dos[i_dos][\"simulation_cell\"].join())\n",
+    "                    continue;\n",
+    "                if(data_k_band[i_k_band][\"atom_positions\"].join() != data_dos[i_dos][\"atom_positions\"].join())\n",
+    "                    continue;\n",
+    "                if(data_k_band[i_k_band][\"atom_labels\"].join() != data_dos[i_dos][\"atom_labels\"].join())\n",
+    "                    continue;\n",
+    "                if(data_k_band[i_k_band][\"XC_functional_name\"] != data_dos[i_dos][\"XC_functional_name\"])\n",
+    "                    continue;\n",
+    "                band_paths.push(data_k_band[i_k_band][\"path\"]);\n",
+    "                dos_paths.push(data_dos[i_dos][\"path\"]);\n",
+    "                N_materials ++;\n",
+    "            }\n",
+    "        }\n",
+    "        //Pass the arrays to python\n",
+    "\n",
+    "        var command = \"N_materials = \" + N_materials + \";\"\n",
+    "        var kernel = IPython.notebook.kernel;\n",
+    "        command += \"band_paths = \" + \"[\\'\" + band_paths.join(\"\\',\\'\") + \"\\'];\";\n",
+    "        command += \"dos_paths = \" + \"[\\'\" + dos_paths.join(\"\\',\\'\") + \"\\'];\";\n",
+    "        kernel.execute(command);\n",
+    "        \n",
+    "        \n",
+    "    }\n",
+    "\n",
+    "    function get_paths_from_search_results(result_json, div_id_search_results,div_head)\n",
+    "    {\n",
+    "        paths = [];\n",
+    "        search_results_content = [div_head, '<table>', '<tr><th>Chemical formula</th><th>Spacegroup</th><th>Code</th><th>XC functional</th><th>Upload ID</th><th>Calculation ID</th><th>URL</th></tr>'];\n",
+    "        for(var i_key in result_json)\n",
+    "        {\n",
+    "            if(i_key == \"results\")\n",
+    "            {\n",
+    "                for(var system in result_json[i_key])\n",
+    "                {\n",
+    "                    //Get the path to the data files (json): https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/upload_id/calc_id \n",
+    "                    path = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/archive/\" + result_json[i_key][system][\"upload_id\"] + \"/\" + result_json[i_key][system][\"calc_id\"]\n",
+    "                    paths.push(path);\n",
+    "                    \n",
+    "                    //Show the results in div\n",
+    "                    // \"formula\" \"spacegroup_symbol\" \"code_name\" \"xc_functional\"\n",
+    "                    content = '<tr>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"formula\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"spacegroup_symbol\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"code_name\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"xc_functional\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"upload_id\"] + '</td>';\n",
+    "                    content += '<td>' + result_json[i_key][system][\"calc_id\"] + '</td>';                    \n",
+    "                    content += '<td>' + path + '</td>';\n",
+    "                    content += '</tr>';\n",
+    "                    search_results_content.push(content);\n",
+    "                }\n",
+    "            }\n",
+    "        }\n",
+    "        search_results_content.push('</table>');\n",
+    "        document.getElementById(div_id_search_results).innerHTML = search_results_content.join('');\n",
+    "        return paths\n",
+    "    }\n",
+    "    \n",
+    "    \n",
+    "    \n",
+    "\n",
+    "    \n",
+    "    \n",
+    "    \n",
+    "    function submit_search()\n",
+    "    {\n",
+    "        \n",
+    "        var result;\n",
+    "        var formula = document.getElementById(\"keyword_chemical_formula\").value;\n",
+    "        var query_command_k_band = \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_k_band_segment\";\n",
+    "        var query_command_dos =  \"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?formula=\" + formula + \"&quantities=section_dos\";\n",
+    "        //result = getJSON(\"https://labdev-nomad.esc.rzg.mpg.de/fairdi/nomad/migration/api/repo/?quantities=section_k_band_segment\");\n",
+    "        var result_k_band = getJSON(query_command_k_band);\n",
+    "        var result_dos = getJSON(query_command_dos);\n",
+    "        var result_json_k_band = JSON.parse(result_k_band);//parse the searching results to json from URL\n",
+    "        var result_json_dos = JSON.parse(result_dos);\n",
+    "        paths_section_k_band_segment = []; \n",
+    "        paths_section_dos = [];\n",
+    "        paths_section_k_band_segment = get_paths_from_search_results(result_json_k_band, \"search_results_section_k_band_segment\", \"<br><br><font size=4em>Calculations containing band structures:</font><br>\");\n",
+    "        paths_section_dos = get_paths_from_search_results(result_json_dos, \"search_results_section_dos\", \"<br><font size=4em>Calculations containing DOS:</font><br>\");\n",
+    "     \n",
+    "        var promise = Promise.resolve();\n",
+    "        promise\n",
+    "            .then(match_band_dos())\n",
+    "            .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')))\n",
+    "            .then(Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')));\n",
+    "        \n",
+    "        //match_band_dos();\n",
+    "              \n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('process_band_dos_data')); //Read the json files, and prepare data for plot\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot')); //Prepare for plot\n",
+    "    }\n",
+    "    function reset_search()\n",
+    "    {\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('search_materials'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_results_and_plot'));\n",
+    "    }\n",
+    "    \n",
+    "    \n",
+    "</script>\n",
+    "<font size=4em>Please input the chemical formula:</font>\n",
+    "<input type=\"text\" id=\"keyword_chemical_formula\" value=\"AlInO3\"> \n",
+    "<button class=\"button\" onclick=\"submit_search()\">Search</button>\n",
+    "<button class=\"button\" onclick=\"reset_search()\">Reset</button>\n",
+    "<br><br><br>\n",
+    "<div id=\"search_results_section_k_band_segment\"></div>\n",
+    "<div id=\"search_results_section_dos\"></div>\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {
+    "tags": [
+     "process_band_dos_data"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "    var band_obj_all = [];\n",
+       "    var dos_obj_all = [];\n",
+       "    var info_obj_all = [];\n",
+       "    //alert(\"process_band_dos_data: \" +band_paths)\n",
+       "    //alert(\"process_band_dos_data: \" +info_obj_all)\n",
+       "    function get_label_flag(coor_array)\n",
+       "    {\n",
+       "        var coor = coor_array.sort().join();\n",
+       "        if(coor == '0,0.5,0.5')\n",
+       "            return \"X\";\n",
+       "        if(coor == '0,0,0.5')\n",
+       "            return \"M\";\n",
+       "        else if(coor == '0.5,0.5,0.5')\n",
+       "            return \"L\";\n",
+       "        else if(coor == '0.375,0.375,0.75')\n",
+       "            return \"K\";\n",
+       "        else if(coor == '0.25,0.5,0.75')\n",
+       "            return \"W\";\n",
+       "        else if(coor == '0,0,0')\n",
+       "            return \"\\u0393\";\n",
+       "        else if(coor == '0.25,0.625,0.625')\n",
+       "            return \"U\";\n",
+       "        else\n",
+       "        {\n",
+       "            //alert(\"k label not found: \" + coor);\n",
+       "            return \"?\";\n",
+       "        }\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    //============Process the band structure data============\n",
+       "    function get_band_obj(band_path, dos_fermi_energy)\n",
+       "    {\n",
+       "        var band_data = JSON.parse(getJSON(band_path));\n",
+       "\n",
+       "        //---------Read section_k_band_segment------------\n",
+       "        var section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n",
+       "\n",
+       "        //--------Get the number of k band segments-------------\n",
+       "        var N_k_band_segments = section_k_band_segment.length;\n",
+       "\n",
+       "\n",
+       "        //----------Get the total number of k points in all segments---------\n",
+       "        var N_k_points_all = 0;\n",
+       "        for(var i = 0; i < N_k_band_segments; i++)\n",
+       "            N_k_points_all = N_k_points_all + section_k_band_segment[i]['band_k_points'].length;\n",
+       "\n",
+       "\n",
+       "        //--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n",
+       "        // store in k_coor_1D[N_k_points_total]-----------------\n",
+       "\n",
+       "        var band_distance_segments = [];\n",
+       "        for(i = 0; i < N_k_band_segments; i++)\n",
+       "        {\n",
+       "            var x1, x2, y1, y2, z1, z2;\n",
+       "            [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end'];  //\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n",
+       "            band_distance_segments.push(Math.pow((x1-x2), 2) + Math.pow((y1-y2), 2) + Math.pow((z1-z2), 2));\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        var band_distance_total = band_distance_segments.reduce((x,y) => x+y); //sum of band_distance_segments\n",
+       "\n",
+       "        var average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total;\n",
+       "\n",
+       "        //Prepare the parameters to rescale the k coordinates into [0,1]\n",
+       "        var step_k_point = 1.0 / N_k_points_all;\n",
+       "        var step_k_point = (1.0 + step_k_point) / N_k_points_all;\n",
+       "\n",
+       "        var k_coor_1D = [];\n",
+       "        for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points ++)\n",
+       "        {\n",
+       "            k_coor_1D.push(step_k_point * i_k_points)\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        //--------Get the eigenvalues of each band trajectory--------------\n",
+       "        /*\n",
+       "        N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n",
+       "        N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n",
+       "        band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n",
+       "        N_k_points_all = 0\n",
+       "        for i_segments in range(N_k_band_segments):\n",
+       "            band_energies = section_k_band_segment[i_segments]['band_energies']\n",
+       "            N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n",
+       "            N_k_points_per_segment = len(band_energies[0])\n",
+       "            for i_k_points in range(N_k_points_per_segment):\n",
+       "                for i_bands in range(N_bands):\n",
+       "                    band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n",
+       "                N_k_points_all = N_k_points_all + 1\n",
+       "        */\n",
+       "        //var N_k_points_per_segment = section_k_band_segment[0]['band_energies'][0].length; //suppose the numebr of k points in all the segments are the same\n",
+       "        var N_bands = section_k_band_segment[0]['band_energies'][0][0].length;\n",
+       "        var band_energies_all = new Array(N_bands);\n",
+       "        for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "            band_energies_all[i_bands] = new Array(N_k_points_all);// new Array(N_bands, N_k_points_all); //store the eigenvalues\n",
+       "\n",
+       "        var i_k_points_all = 0;\n",
+       "\n",
+       "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+       "        {\n",
+       "            var band_energies = section_k_band_segment[i_segments]['band_energies'];\n",
+       "            var N_spin_channel = band_energies.length; //Number of the spin channel --FIXME: no spin polarized\n",
+       "            var N_k_points_per_segment = band_energies[0].length;\n",
+       "            for(var i_k_points = 0; i_k_points < N_k_points_per_segment; i_k_points ++)\n",
+       "            {\n",
+       "                for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "                {\n",
+       "                    band_energies_all[i_bands][i_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * Math.pow(10, -19)) - dos_fermi_energy;\n",
+       "                }\n",
+       "                i_k_points_all = i_k_points_all + 1 ;\n",
+       "\n",
+       "            }\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "\n",
+       "        var N_labels = 0\n",
+       "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+       "        {\n",
+       "            for(var j = 0; j < 2; j++)\n",
+       "                //labels_tmp =  section_k_band_segment[i_segments]['band_segm_start_end'][j];\n",
+       "                N_labels = N_labels + 1\n",
+       "        }\n",
+       "        var label_flag = [];//[\"\" for i in range(N_labels)] //stores the flags of the labels (X, W, G, etc)\n",
+       "\n",
+       "\n",
+       "        var i_label = 0;\n",
+       "        var label_flag_last_final = \"\";\n",
+       "        var label_flag_current_initial = \"\";\n",
+       "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+       "        {\n",
+       "            var labels_coor_0 =  section_k_band_segment[i_segments]['band_segm_start_end'][0].sort();\n",
+       "            var labels_coor_1 =  section_k_band_segment[i_segments]['band_segm_start_end'][1].sort();\n",
+       "\n",
+       "            var label_flag_0 = get_label_flag(labels_coor_0);\n",
+       "            var label_flag_1 = get_label_flag(labels_coor_1);\n",
+       "\n",
+       "            var label_flag_current_initial = label_flag_0;\n",
+       "            if(label_flag_last_final == \"\")\n",
+       "                label_flag_last_final = label_flag_0;\n",
+       "\n",
+       "            if(label_flag_last_final == label_flag_current_initial)\n",
+       "                label_flag[i_label] = label_flag_current_initial;\n",
+       "            else\n",
+       "                label_flag[i_label] = label_flag_last_final + '|' + label_flag_current_initial;\n",
+       "            label_flag_last_final = label_flag_1\n",
+       "\n",
+       "\n",
+       "            i_label = i_label + 1;\n",
+       "            if(i_segments == N_k_band_segments - 1)\n",
+       "            {\n",
+       "                label_flag[i_label] = label_flag_1;\n",
+       "                i_label = i_label + 1;\n",
+       "            }\n",
+       "        }\n",
+       "        N_labels = i_label;\n",
+       "\n",
+       "        //------------Get the coordinates for the labels------------\n",
+       "        //label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n",
+       "        var label_coor_relative = [];//np.zeros((N_labels))\n",
+       "        for(i_label = 0; i_label < N_labels; i_label ++)\n",
+       "        {\n",
+       "            //Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n",
+       "            //x = labels_coor_0[0]\n",
+       "            //y = labels_coor_0[1]\n",
+       "            //z = labels_coor_0[2]\n",
+       "            //label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n",
+       "            label_coor_relative.push(step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all));\n",
+       "        }\n",
+       "        //----Store the label-----------\n",
+       "        var label_obj = [];//[['' for i in range(2)] for j in range(N_labels)]\n",
+       "        for(i_label = 0; i_label < N_labels; i_label ++)\n",
+       "        {\n",
+       "            label_obj.push([label_coor_relative[i_label], label_flag[i_label]]);\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        //-------Get VBM, CBM----------------\n",
+       "\n",
+       "        var HOMO = -1000;\n",
+       "        var LUMO = 1000;\n",
+       "        var coor_k_point_HOMO = []; //the coordinate of k point that stores HOMO\n",
+       "        var coor_k_point_LUMO = [];//np.zeros((3)) #the coordinate of k point that stores LUMO\n",
+       "        //band_gap_direct = 0.0\n",
+       "        var band_gap_indirect = 0.0;\n",
+       "\n",
+       "\n",
+       "        //band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+       "        //band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+       "        var band_energy_max = 10;\n",
+       "        var band_energy_min = -10;\n",
+       "        //N_band_energy_index = 10000\n",
+       "        //band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n",
+       "        //N_allowed_states = np.zeros(N_band_energy_index + 1)\n",
+       "        //i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n",
+       "\n",
+       "\n",
+       "        for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "        {\n",
+       "            for(var i_k_points_all = 0; i_k_points_all< N_k_points_all; i_k_points_all ++)\n",
+       "            {\n",
+       "                //i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n",
+       "                //N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n",
+       "                var band_energy = band_energies_all[i_bands][i_k_points_all];\n",
+       "                if(band_energy > 0)\n",
+       "                {\n",
+       "                    if(band_energy < LUMO)\n",
+       "                        LUMO = band_energy;\n",
+       "                }\n",
+       "                else\n",
+       "                {\n",
+       "                    if(band_energy > HOMO)\n",
+       "                        HOMO = band_energy;\n",
+       "                }\n",
+       "\n",
+       "            }\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        //#for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n",
+       "        //    if(N_allowed_states[i_band_index] > 0):\n",
+       "        //        LUMO = band_energy_min + band_energy_step * i_band_index\n",
+       "        //print('HOMO, LUMO: ',HOMO, LUMO)\n",
+       "        band_gap_indirect = Math.abs(LUMO - HOMO);\n",
+       "\n",
+       "        if(band_gap_indirect < 0.5) //VBM and CBM has to be found in another way for metals/charged system:\n",
+       "        {\n",
+       "            HOMO = -1000.0;\n",
+       "            LUMO = 1000.0;\n",
+       "            band_energy_max = 10.0;\n",
+       "            band_energy_min = 0.0;\n",
+       "            var N_band_energy_index = 10000;\n",
+       "            var band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index;\n",
+       "            var N_allowed_states = [];\n",
+       "            for(var i_state = 0; i_state < N_band_energy_index+1; i_state++)\n",
+       "                N_allowed_states.push(0);\n",
+       "\n",
+       "\n",
+       "            //get the DOS and store in N_allowed_states[]\n",
+       "            for(var i_k_points_all = 0; i_k_points_all < N_k_points_all; i_k_points_all ++)\n",
+       "            {\n",
+       "                for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "                {\n",
+       "                    var band_energy = band_energies_all[i_bands][i_k_points_all];\n",
+       "                    if((band_energy_min < band_energy)&&(band_energy < band_energy_max))\n",
+       "                    {\n",
+       "                        var i_band_index = Math.floor((band_energy - band_energy_min) / band_energy_step);\n",
+       "                        N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1;\n",
+       "                    }\n",
+       "                }\n",
+       "            }\n",
+       "\n",
+       "\n",
+       "            var if_gapped = 0;\n",
+       "            for(var i_band_index = 0; i_band_index < N_band_energy_index; i_band_index ++)//go through the energy levels from the bottom\n",
+       "            {\n",
+       "                var band_energy = band_energy_min + band_energy_step * i_band_index\n",
+       "                if(N_allowed_states[i_band_index] == 0)\n",
+       "                    if_gapped = if_gapped + 1;\n",
+       "                if((band_energy > band_energy_max - 0.5) && (if_gapped == 0))\n",
+       "                {\n",
+       "                    //alert(\"No gap found in this system. It seems to be a metal.\");\n",
+       "                    HOMO = 1000;\n",
+       "                    LUMO = 1000;\n",
+       "                    break;\n",
+       "                }\n",
+       "                //print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n",
+       "\n",
+       "                if(N_allowed_states[i_band_index] > 0)\n",
+       "                {\n",
+       "                    if(if_gapped * band_energy_step > 0.3 )//above VBM-CBM gap: LUMO\n",
+       "                    {\n",
+       "                        if(band_energy < LUMO)\n",
+       "                        {\n",
+       "                            //print(\"LUMO got!\")\n",
+       "                            LUMO = band_energy;\n",
+       "                            break; //break before touching another gap that is above the band gap\n",
+       "                        }\n",
+       "                    }\n",
+       "\n",
+       "                    if(if_gapped * band_energy_step < 0.3) //below VBM-CBM gap: HOMO\n",
+       "                    {\n",
+       "                        if(band_energy > HOMO)\n",
+       "                        {\n",
+       "                            //print(\"HOMO got!\")\n",
+       "                            HOMO = band_energy;\n",
+       "                        }\n",
+       "                    }        \n",
+       "                    if_gapped = 0;\n",
+       "                }\n",
+       "            }\n",
+       "            //alert('HOMO, LUMO for metal/charged system: '+ HOMO +\",\"+LUMO)\n",
+       "\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "\n",
+       "\n",
+       "        //Find the position of HOMO, LUMO\n",
+       "        var coor_k_point_HOMO = 0, coor_k_point_LUMO = 0;\n",
+       "        for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points++)\n",
+       "        {\n",
+       "            for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+       "            {\n",
+       "                if(Math.abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001)\n",
+       "                    coor_k_point_HOMO = k_coor_1D[i_k_points];\n",
+       "                if(Math.abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001)\n",
+       "                    coor_k_point_LUMO = k_coor_1D[i_k_points]; \n",
+       "            }\n",
+       "        }\n",
+       "\n",
+       "        //alert(coor_k_point_HOMO +\",\" + coor_k_point_LUMO);\n",
+       "\n",
+       "\n",
+       "        //Store the band data to band_obj\n",
+       "\n",
+       "        var band_obj = {};\n",
+       "        band_obj[\"band_x_axis\"] = k_coor_1D;\n",
+       "        band_obj[\"band_y_axis\"] = band_energies_all\n",
+       "        band_obj[\"labels\"] = label_obj;\n",
+       "        band_obj[\"HOMO_energy\"] = HOMO;\n",
+       "        band_obj[\"HOMO_coor\"] = coor_k_point_HOMO;\n",
+       "        band_obj[\"LUMO_energy\"] = LUMO;\n",
+       "        band_obj[\"LUMO_coor\"] = coor_k_point_LUMO;\n",
+       "        band_obj[\"average_N_k_points_per_inverse_distance\"] = average_N_k_points_per_inverse_distance;\n",
+       "\n",
+       "\n",
+       "        return band_obj\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    function get_dos_obj(dos_path)\n",
+       "    {\n",
+       "\n",
+       "        var dos_data = JSON.parse(getJSON(dos_path));\n",
+       "\n",
+       "        var N_dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'].length;\n",
+       "\n",
+       "        //in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n",
+       "\n",
+       "        //dos_energies = new Array(N_dos_values).fill(0.0);\n",
+       "        //dos_energies_tmp = new Array(N_dos_values).fill(0.0) #tmp array for unit convertion\n",
+       "        //dos_values = new Array(N_dos_values).fill(0.0)\n",
+       "\n",
+       "        var dos_energies = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'];\n",
+       "        var dos_values =  dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_integrated_values'];//[0]\n",
+       "\n",
+       "        //To do: check if every section_dos has 'dos_fermi_energy'\n",
+       "        var dos_fermi_energy = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_fermi_energy'];\n",
+       "        dos_fermi_energy = dos_fermi_energy  / (1.60217656535 * Math.pow(10,-19));\n",
+       "        \n",
+       "        for(var i = 0; i < N_dos_values; i++)\n",
+       "        {\n",
+       "            dos_energies[i] = dos_energies[i] / (1.60217656535 * Math.pow(10,-19)) - dos_fermi_energy;\n",
+       "        }\n",
+       "        \n",
+       "        dos_obj = {}\n",
+       "        dos_obj[\"dos_x_axis\"] = dos_energies;\n",
+       "        dos_obj[\"dos_y_axis\"] = dos_values;\n",
+       "        dos_obj[\"dos_fermi_energy\"] = dos_fermi_energy;\n",
+       "        return dos_obj\n",
+       "    }\n",
+       "    function get_info_obj(band_path)\n",
+       "    {\n",
+       "\n",
+       "        var band_data = JSON.parse(getJSON(band_path));\n",
+       "        var info_obj = {};\n",
+       "        //---------Read the information of the calculation--------\n",
+       "        info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n",
+       "        info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n",
+       "        info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+       "        info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n",
+       "\n",
+       "        //----------Get the space group information----------\n",
+       "        /*\n",
+       "        [space_group_symbol, lattice_constant] = get_space_group(band_data);\n",
+       "        info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist();\n",
+       "        info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist();\n",
+       "        */\n",
+       "\n",
+       "        return info_obj\n",
+       "    }\n",
+       "    function process_band_dos_data()\n",
+       "    {\n",
+       "        info_all = [];\n",
+       "        band_obj_all = [];\n",
+       "        dos_obj_all = [];\n",
+       "\n",
+       "        for(var i = 0; i < N_materials; i++)\n",
+       "        {\n",
+       "            var band_path = band_paths[i];\n",
+       "            var dos_path = dos_paths[i];\n",
+       "\n",
+       "\n",
+       "            var dos_obj = get_dos_obj(dos_path);\n",
+       "            var dos_fermi_energy = dos_obj[\"dos_fermi_energy\"];\n",
+       "            band_obj = get_band_obj(band_path, dos_fermi_energy);\n",
+       "            var info_obj = get_info_obj(band_path);\n",
+       "\n",
+       "            band_obj_all.push(band_obj);\n",
+       "            dos_obj_all.push(dos_obj);\n",
+       "            info_obj_all.push(info_obj);\n",
+       "        }\n",
+       "    }\n",
+       "    process_band_dos_data();\n",
+       "    //alert(\"process_band_dos_data: info_obj_all: \"+JSON.stringify(info_obj_all));\n",
+       "</script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "    var band_obj_all = [];\n",
+    "    var dos_obj_all = [];\n",
+    "    var info_obj_all = [];\n",
+    "    //alert(\"process_band_dos_data: \" +band_paths)\n",
+    "    //alert(\"process_band_dos_data: \" +info_obj_all)\n",
+    "    function get_label_flag(coor_array)\n",
+    "    {\n",
+    "        var coor = coor_array.sort().join();\n",
+    "        if(coor == '0,0.5,0.5')\n",
+    "            return \"X\";\n",
+    "        if(coor == '0,0,0.5')\n",
+    "            return \"M\";\n",
+    "        else if(coor == '0.5,0.5,0.5')\n",
+    "            return \"L\";\n",
+    "        else if(coor == '0.375,0.375,0.75')\n",
+    "            return \"K\";\n",
+    "        else if(coor == '0.25,0.5,0.75')\n",
+    "            return \"W\";\n",
+    "        else if(coor == '0,0,0')\n",
+    "            return \"\\u0393\";\n",
+    "        else if(coor == '0.25,0.625,0.625')\n",
+    "            return \"U\";\n",
+    "        else\n",
+    "        {\n",
+    "            //alert(\"k label not found: \" + coor);\n",
+    "            return \"?\";\n",
+    "        }\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    //============Process the band structure data============\n",
+    "    function get_band_obj(band_path, dos_fermi_energy)\n",
+    "    {\n",
+    "        var band_data = JSON.parse(getJSON(band_path));\n",
+    "\n",
+    "        //---------Read section_k_band_segment------------\n",
+    "        var section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n",
+    "\n",
+    "        //--------Get the number of k band segments-------------\n",
+    "        var N_k_band_segments = section_k_band_segment.length;\n",
+    "\n",
+    "\n",
+    "        //----------Get the total number of k points in all segments---------\n",
+    "        var N_k_points_all = 0;\n",
+    "        for(var i = 0; i < N_k_band_segments; i++)\n",
+    "            N_k_points_all = N_k_points_all + section_k_band_segment[i]['band_k_points'].length;\n",
+    "\n",
+    "\n",
+    "        //--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n",
+    "        // store in k_coor_1D[N_k_points_total]-----------------\n",
+    "\n",
+    "        var band_distance_segments = [];\n",
+    "        for(i = 0; i < N_k_band_segments; i++)\n",
+    "        {\n",
+    "            var x1, x2, y1, y2, z1, z2;\n",
+    "            [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end'];  //\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n",
+    "            band_distance_segments.push(Math.pow((x1-x2), 2) + Math.pow((y1-y2), 2) + Math.pow((z1-z2), 2));\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        var band_distance_total = band_distance_segments.reduce((x,y) => x+y); //sum of band_distance_segments\n",
+    "\n",
+    "        var average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total;\n",
+    "\n",
+    "        //Prepare the parameters to rescale the k coordinates into [0,1]\n",
+    "        var step_k_point = 1.0 / N_k_points_all;\n",
+    "        var step_k_point = (1.0 + step_k_point) / N_k_points_all;\n",
+    "\n",
+    "        var k_coor_1D = [];\n",
+    "        for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points ++)\n",
+    "        {\n",
+    "            k_coor_1D.push(step_k_point * i_k_points)\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        //--------Get the eigenvalues of each band trajectory--------------\n",
+    "        /*\n",
+    "        N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n",
+    "        N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n",
+    "        band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n",
+    "        N_k_points_all = 0\n",
+    "        for i_segments in range(N_k_band_segments):\n",
+    "            band_energies = section_k_band_segment[i_segments]['band_energies']\n",
+    "            N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n",
+    "            N_k_points_per_segment = len(band_energies[0])\n",
+    "            for i_k_points in range(N_k_points_per_segment):\n",
+    "                for i_bands in range(N_bands):\n",
+    "                    band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n",
+    "                N_k_points_all = N_k_points_all + 1\n",
+    "        */\n",
+    "        //var N_k_points_per_segment = section_k_band_segment[0]['band_energies'][0].length; //suppose the numebr of k points in all the segments are the same\n",
+    "        var N_bands = section_k_band_segment[0]['band_energies'][0][0].length;\n",
+    "        var band_energies_all = new Array(N_bands);\n",
+    "        for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "            band_energies_all[i_bands] = new Array(N_k_points_all);// new Array(N_bands, N_k_points_all); //store the eigenvalues\n",
+    "\n",
+    "        var i_k_points_all = 0;\n",
+    "\n",
+    "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+    "        {\n",
+    "            var band_energies = section_k_band_segment[i_segments]['band_energies'];\n",
+    "            var N_spin_channel = band_energies.length; //Number of the spin channel --FIXME: no spin polarized\n",
+    "            var N_k_points_per_segment = band_energies[0].length;\n",
+    "            for(var i_k_points = 0; i_k_points < N_k_points_per_segment; i_k_points ++)\n",
+    "            {\n",
+    "                for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "                {\n",
+    "                    band_energies_all[i_bands][i_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * Math.pow(10, -19)) - dos_fermi_energy;\n",
+    "                }\n",
+    "                i_k_points_all = i_k_points_all + 1 ;\n",
+    "\n",
+    "            }\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "\n",
+    "        var N_labels = 0\n",
+    "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+    "        {\n",
+    "            for(var j = 0; j < 2; j++)\n",
+    "                //labels_tmp =  section_k_band_segment[i_segments]['band_segm_start_end'][j];\n",
+    "                N_labels = N_labels + 1\n",
+    "        }\n",
+    "        var label_flag = [];//[\"\" for i in range(N_labels)] //stores the flags of the labels (X, W, G, etc)\n",
+    "\n",
+    "\n",
+    "        var i_label = 0;\n",
+    "        var label_flag_last_final = \"\";\n",
+    "        var label_flag_current_initial = \"\";\n",
+    "        for(var i_segments = 0; i_segments < N_k_band_segments; i_segments ++)\n",
+    "        {\n",
+    "            var labels_coor_0 =  section_k_band_segment[i_segments]['band_segm_start_end'][0].sort();\n",
+    "            var labels_coor_1 =  section_k_band_segment[i_segments]['band_segm_start_end'][1].sort();\n",
+    "\n",
+    "            var label_flag_0 = get_label_flag(labels_coor_0);\n",
+    "            var label_flag_1 = get_label_flag(labels_coor_1);\n",
+    "\n",
+    "            var label_flag_current_initial = label_flag_0;\n",
+    "            if(label_flag_last_final == \"\")\n",
+    "                label_flag_last_final = label_flag_0;\n",
+    "\n",
+    "            if(label_flag_last_final == label_flag_current_initial)\n",
+    "                label_flag[i_label] = label_flag_current_initial;\n",
+    "            else\n",
+    "                label_flag[i_label] = label_flag_last_final + '|' + label_flag_current_initial;\n",
+    "            label_flag_last_final = label_flag_1\n",
+    "\n",
+    "\n",
+    "            i_label = i_label + 1;\n",
+    "            if(i_segments == N_k_band_segments - 1)\n",
+    "            {\n",
+    "                label_flag[i_label] = label_flag_1;\n",
+    "                i_label = i_label + 1;\n",
+    "            }\n",
+    "        }\n",
+    "        N_labels = i_label;\n",
+    "\n",
+    "        //------------Get the coordinates for the labels------------\n",
+    "        //label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n",
+    "        var label_coor_relative = [];//np.zeros((N_labels))\n",
+    "        for(i_label = 0; i_label < N_labels; i_label ++)\n",
+    "        {\n",
+    "            //Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n",
+    "            //x = labels_coor_0[0]\n",
+    "            //y = labels_coor_0[1]\n",
+    "            //z = labels_coor_0[2]\n",
+    "            //label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n",
+    "            label_coor_relative.push(step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all));\n",
+    "        }\n",
+    "        //----Store the label-----------\n",
+    "        var label_obj = [];//[['' for i in range(2)] for j in range(N_labels)]\n",
+    "        for(i_label = 0; i_label < N_labels; i_label ++)\n",
+    "        {\n",
+    "            label_obj.push([label_coor_relative[i_label], label_flag[i_label]]);\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        //-------Get VBM, CBM----------------\n",
+    "\n",
+    "        var HOMO = -1000;\n",
+    "        var LUMO = 1000;\n",
+    "        var coor_k_point_HOMO = []; //the coordinate of k point that stores HOMO\n",
+    "        var coor_k_point_LUMO = [];//np.zeros((3)) #the coordinate of k point that stores LUMO\n",
+    "        //band_gap_direct = 0.0\n",
+    "        var band_gap_indirect = 0.0;\n",
+    "\n",
+    "\n",
+    "        //band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+    "        //band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+    "        var band_energy_max = 10;\n",
+    "        var band_energy_min = -10;\n",
+    "        //N_band_energy_index = 10000\n",
+    "        //band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n",
+    "        //N_allowed_states = np.zeros(N_band_energy_index + 1)\n",
+    "        //i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n",
+    "\n",
+    "\n",
+    "        for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "        {\n",
+    "            for(var i_k_points_all = 0; i_k_points_all< N_k_points_all; i_k_points_all ++)\n",
+    "            {\n",
+    "                //i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n",
+    "                //N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n",
+    "                var band_energy = band_energies_all[i_bands][i_k_points_all];\n",
+    "                if(band_energy > 0)\n",
+    "                {\n",
+    "                    if(band_energy < LUMO)\n",
+    "                        LUMO = band_energy;\n",
+    "                }\n",
+    "                else\n",
+    "                {\n",
+    "                    if(band_energy > HOMO)\n",
+    "                        HOMO = band_energy;\n",
+    "                }\n",
+    "\n",
+    "            }\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        //#for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n",
+    "        //    if(N_allowed_states[i_band_index] > 0):\n",
+    "        //        LUMO = band_energy_min + band_energy_step * i_band_index\n",
+    "        //print('HOMO, LUMO: ',HOMO, LUMO)\n",
+    "        band_gap_indirect = Math.abs(LUMO - HOMO);\n",
+    "\n",
+    "        if(band_gap_indirect < 0.5) //VBM and CBM has to be found in another way for metals/charged system:\n",
+    "        {\n",
+    "            HOMO = -1000.0;\n",
+    "            LUMO = 1000.0;\n",
+    "            band_energy_max = 10.0;\n",
+    "            band_energy_min = 0.0;\n",
+    "            var N_band_energy_index = 10000;\n",
+    "            var band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index;\n",
+    "            var N_allowed_states = [];\n",
+    "            for(var i_state = 0; i_state < N_band_energy_index+1; i_state++)\n",
+    "                N_allowed_states.push(0);\n",
+    "\n",
+    "\n",
+    "            //get the DOS and store in N_allowed_states[]\n",
+    "            for(var i_k_points_all = 0; i_k_points_all < N_k_points_all; i_k_points_all ++)\n",
+    "            {\n",
+    "                for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "                {\n",
+    "                    var band_energy = band_energies_all[i_bands][i_k_points_all];\n",
+    "                    if((band_energy_min < band_energy)&&(band_energy < band_energy_max))\n",
+    "                    {\n",
+    "                        var i_band_index = Math.floor((band_energy - band_energy_min) / band_energy_step);\n",
+    "                        N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1;\n",
+    "                    }\n",
+    "                }\n",
+    "            }\n",
+    "\n",
+    "\n",
+    "            var if_gapped = 0;\n",
+    "            for(var i_band_index = 0; i_band_index < N_band_energy_index; i_band_index ++)//go through the energy levels from the bottom\n",
+    "            {\n",
+    "                var band_energy = band_energy_min + band_energy_step * i_band_index\n",
+    "                if(N_allowed_states[i_band_index] == 0)\n",
+    "                    if_gapped = if_gapped + 1;\n",
+    "                if((band_energy > band_energy_max - 0.5) && (if_gapped == 0))\n",
+    "                {\n",
+    "                    //alert(\"No gap found in this system. It seems to be a metal.\");\n",
+    "                    HOMO = 1000;\n",
+    "                    LUMO = 1000;\n",
+    "                    break;\n",
+    "                }\n",
+    "                //print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n",
+    "\n",
+    "                if(N_allowed_states[i_band_index] > 0)\n",
+    "                {\n",
+    "                    if(if_gapped * band_energy_step > 0.3 )//above VBM-CBM gap: LUMO\n",
+    "                    {\n",
+    "                        if(band_energy < LUMO)\n",
+    "                        {\n",
+    "                            //print(\"LUMO got!\")\n",
+    "                            LUMO = band_energy;\n",
+    "                            break; //break before touching another gap that is above the band gap\n",
+    "                        }\n",
+    "                    }\n",
+    "\n",
+    "                    if(if_gapped * band_energy_step < 0.3) //below VBM-CBM gap: HOMO\n",
+    "                    {\n",
+    "                        if(band_energy > HOMO)\n",
+    "                        {\n",
+    "                            //print(\"HOMO got!\")\n",
+    "                            HOMO = band_energy;\n",
+    "                        }\n",
+    "                    }        \n",
+    "                    if_gapped = 0;\n",
+    "                }\n",
+    "            }\n",
+    "            //alert('HOMO, LUMO for metal/charged system: '+ HOMO +\",\"+LUMO)\n",
+    "\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n",
+    "        //Find the position of HOMO, LUMO\n",
+    "        var coor_k_point_HOMO = 0, coor_k_point_LUMO = 0;\n",
+    "        for(var i_k_points = 0; i_k_points < N_k_points_all; i_k_points++)\n",
+    "        {\n",
+    "            for(var i_bands = 0; i_bands < N_bands; i_bands ++)\n",
+    "            {\n",
+    "                if(Math.abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001)\n",
+    "                    coor_k_point_HOMO = k_coor_1D[i_k_points];\n",
+    "                if(Math.abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001)\n",
+    "                    coor_k_point_LUMO = k_coor_1D[i_k_points]; \n",
+    "            }\n",
+    "        }\n",
+    "\n",
+    "        //alert(coor_k_point_HOMO +\",\" + coor_k_point_LUMO);\n",
+    "\n",
+    "\n",
+    "        //Store the band data to band_obj\n",
+    "\n",
+    "        var band_obj = {};\n",
+    "        band_obj[\"band_x_axis\"] = k_coor_1D;\n",
+    "        band_obj[\"band_y_axis\"] = band_energies_all\n",
+    "        band_obj[\"labels\"] = label_obj;\n",
+    "        band_obj[\"HOMO_energy\"] = HOMO;\n",
+    "        band_obj[\"HOMO_coor\"] = coor_k_point_HOMO;\n",
+    "        band_obj[\"LUMO_energy\"] = LUMO;\n",
+    "        band_obj[\"LUMO_coor\"] = coor_k_point_LUMO;\n",
+    "        band_obj[\"average_N_k_points_per_inverse_distance\"] = average_N_k_points_per_inverse_distance;\n",
+    "\n",
+    "\n",
+    "        return band_obj\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    function get_dos_obj(dos_path)\n",
+    "    {\n",
+    "\n",
+    "        var dos_data = JSON.parse(getJSON(dos_path));\n",
+    "\n",
+    "        var N_dos_values = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'].length;\n",
+    "\n",
+    "        //in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n",
+    "\n",
+    "        //dos_energies = new Array(N_dos_values).fill(0.0);\n",
+    "        //dos_energies_tmp = new Array(N_dos_values).fill(0.0) #tmp array for unit convertion\n",
+    "        //dos_values = new Array(N_dos_values).fill(0.0)\n",
+    "\n",
+    "        var dos_energies = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'];\n",
+    "        var dos_values =  dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_integrated_values'];//[0]\n",
+    "\n",
+    "        //To do: check if every section_dos has 'dos_fermi_energy'\n",
+    "        var dos_fermi_energy = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_fermi_energy'];\n",
+    "        dos_fermi_energy = dos_fermi_energy  / (1.60217656535 * Math.pow(10,-19));\n",
+    "        \n",
+    "        for(var i = 0; i < N_dos_values; i++)\n",
+    "        {\n",
+    "            dos_energies[i] = dos_energies[i] / (1.60217656535 * Math.pow(10,-19)) - dos_fermi_energy;\n",
+    "        }\n",
+    "        \n",
+    "        dos_obj = {}\n",
+    "        dos_obj[\"dos_x_axis\"] = dos_energies;\n",
+    "        dos_obj[\"dos_y_axis\"] = dos_values;\n",
+    "        dos_obj[\"dos_fermi_energy\"] = dos_fermi_energy;\n",
+    "        return dos_obj\n",
+    "    }\n",
+    "    function get_info_obj(band_path)\n",
+    "    {\n",
+    "\n",
+    "        var band_data = JSON.parse(getJSON(band_path));\n",
+    "        var info_obj = {};\n",
+    "        //---------Read the information of the calculation--------\n",
+    "        info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n",
+    "        info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n",
+    "        info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+    "        info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n",
+    "\n",
+    "        //----------Get the space group information----------\n",
+    "        /*\n",
+    "        [space_group_symbol, lattice_constant] = get_space_group(band_data);\n",
+    "        info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist();\n",
+    "        info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist();\n",
+    "        */\n",
+    "\n",
+    "        return info_obj\n",
+    "    }\n",
+    "    function process_band_dos_data()\n",
+    "    {\n",
+    "        info_all = [];\n",
+    "        band_obj_all = [];\n",
+    "        dos_obj_all = [];\n",
+    "\n",
+    "        for(var i = 0; i < N_materials; i++)\n",
+    "        {\n",
+    "            var band_path = band_paths[i];\n",
+    "            var dos_path = dos_paths[i];\n",
+    "\n",
+    "\n",
+    "            var dos_obj = get_dos_obj(dos_path);\n",
+    "            var dos_fermi_energy = dos_obj[\"dos_fermi_energy\"];\n",
+    "            band_obj = get_band_obj(band_path, dos_fermi_energy);\n",
+    "            var info_obj = get_info_obj(band_path);\n",
+    "\n",
+    "            band_obj_all.push(band_obj);\n",
+    "            dos_obj_all.push(dos_obj);\n",
+    "            info_obj_all.push(info_obj);\n",
+    "        }\n",
+    "    }\n",
+    "    process_band_dos_data();\n",
+    "    //alert(\"process_band_dos_data: info_obj_all: \"+JSON.stringify(info_obj_all));\n",
+    "</script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 54,
+   "metadata": {
+    "scrolled": false,
+    "tags": [
+     "show_results_and_plot"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script>\n",
+       "    var N_max_show = 10; //Number of results to be shown by default\n",
+       "\n",
+       "    function show_materials_submitted_info()\n",
+       "    {\n",
+       "      //alert(\"N_materials=\" + N_materials)\n",
+       "      //\"table_materials_submitted_info\"\n",
+       "      //alert(\"show_materials_submitted_info: info_obj_all: \"+JSON.stringify(info_obj_all))\n",
+       "      var table_content = new Array(); \n",
+       "      str = '<tr>';\n",
+       "      str += '<th width=\"5%\"></th>'\n",
+       "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Atom labels</b></font></p></th>';\n",
+       "      //str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Space group</b></font></p></th>';\n",
+       "      //str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Lattice constants (in Ang)</b></font></p></th>';\n",
+       "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Program name</b></font></p></th>';\n",
+       "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Basis set type</b></font></p></th>';\n",
+       "      str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Functional</b></font></p></th>';\n",
+       "      //str += '<th width=\"20%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Number of <i>k</i> points per inverse distance</b></font></p></th>';\n",
+       "      str += '</tr>'; //first row: head\n",
+       "      table_content.push(str);\n",
+       "\n",
+       "      for(var i = 0; i < N_materials; i++) //add info of each material\n",
+       "      {\n",
+       "        //alert(\"show_materials_submitted_info: material \"+ i);  \n",
+       "        table_content.push('<tr>');\n",
+       "\n",
+       "        table_content.push('<td>');    \n",
+       "        str = '<input type = \\\"checkbox\\\" name = \"checkbox_material\" id = \\\"checkbox_material' + i.toString() + '\\\" unchecked  onclick=\\\"checkbox_material(this.id)\\\">';\n",
+       "        str += \"<b>&nbsp&nbsp#\" + (i+1).toString() + \"</b>\";\n",
+       "        table_content.push(str);\n",
+       "        table_content.push('</td>');\n",
+       "\n",
+       "        table_content.push('<td>');    \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"atom_labels\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got atom_labels\");\n",
+       "\n",
+       "        /*\n",
+       "        table_content.push('<td>');    \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"space_group_symbol\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got space_group_symbol\");\n",
+       "\n",
+       "        table_content.push('<td>');    \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"lattice_constant\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got lattice_constant\");\n",
+       "        */\n",
+       "          \n",
+       "        table_content.push('<td>'); \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"program_name\"].toUpperCase() + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got program_name\");\n",
+       "\n",
+       "        table_content.push('<td>'); \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"program_basis_set_type\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got program_basis_set_type\");\n",
+       "\n",
+       "\n",
+       "        table_content.push('<td>'); \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += info_obj_all[i][\"XC_functional_name\"] + '; &nbsp&nbsp';\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got XC_functional_name\");\n",
+       "\n",
+       "        /*\n",
+       "        table_content.push('<td>'); \n",
+       "        str = '<font size = \\\"3pt\\\">';\n",
+       "        str += band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+       "        str += \"</font>\"\n",
+       "        table_content.push(str);    \n",
+       "        table_content.push('</td>');\n",
+       "        //alert(\"got average_N_k_points_per_inverse_distance\");\n",
+       "        */\n",
+       "        table_content.push('</tr>');\n",
+       "\n",
+       "      }\n",
+       "      \n",
+       "      document.getElementById(\"table_materials_submitted_info\").innerHTML = table_content.join('');\n",
+       "    }\n",
+       "\n",
+       "    function clean_materials_selection()\n",
+       "    {\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_material\");\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "      {\n",
+       "        //choices_compare[i].removeAttribute('checked');\n",
+       "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+       "        choices_compare[i].checked = \"\";\n",
+       "      }\n",
+       "    }\n",
+       "\n",
+       "    function select_all()\n",
+       "    {\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_material\");\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "      {\n",
+       "        //choices_compare[i].removeAttribute('checked');\n",
+       "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+       "        choices_compare[i].checked = \"checked\";\n",
+       "      }\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "\n",
+       "    function process()\n",
+       "    {\n",
+       "        //alert(\"Process:\"+band_paths)\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_js_plot'));\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_materials_submitted_info'));\n",
+       "        show_materials_submitted_info();\n",
+       "        document.getElementById(\"table_visualize\").innerHTML = \"\";\n",
+       "        str = N_materials.toString();\n",
+       "        document.getElementById(\"n_materials\").innerHTML = \"Number of materials submitted: \" + str + \"<font size = 1px color = #C0C0C0  > &nbsp Please press \\'Visualize\\' to visualize the band structure. </font>\";\n",
+       "        document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n",
+       "    }\n",
+       "        \n",
+       "\n",
+       "    var image_band = '';\n",
+       "    var image_dos = '';\n",
+       "    var image_band_links = new Array(N_materials); //store the URL of each band figure -> used to compare 2 figures\n",
+       "    var image_band_links_selected = [];\n",
+       "    var image_band_selected_Number = []; //record which i_material has been selected\n",
+       "\n",
+       "\n",
+       "\n",
+       "    function prepare(N_materials_show)\n",
+       "    {\n",
+       "      document.getElementById(\"table_visualize\").innerHTML = \"\";\n",
+       "      var table_content = new Array(); \n",
+       "      //document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n",
+       "      //-----Generate the html tables for each material--------\n",
+       "      for(var i = 0; i < N_materials_show; i++)\n",
+       "      {\n",
+       "        checkbox_material_id = \"checkbox_material\" + i.toString();\n",
+       "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+       "        if(if_selected != 1)\n",
+       "        {\n",
+       "          continue;\n",
+       "        }\n",
+       "\n",
+       "        table_content.push('<tr>');\n",
+       "        div_string = '<div style = \\\"height: 20px\\\"></div>';\n",
+       "        table_content.push(div_string);\n",
+       "        table_content.push('<th>');\n",
+       "\n",
+       "        //add main container div\n",
+       "        div_string = '<div id = \\\"div_band_dos' + i.toString() + '\\\" class = \\\"div_band_dos\\\" >';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //show No. of the material\n",
+       "        i_material = i + 1;\n",
+       "        div_string = '<div style = \\\"height:30px\\; font-size: 15pt;\">' + '#' + i_material.toString() + '</div>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //show band_path/dos info\n",
+       "        div_string = '<div style = \\\"height:30px\\\">' + 'Band: &nbsp&nbsp' + band_paths[i] + ',&nbsp&nbsp&nbsp&nbspDOS: &nbsp&nbsp' + dos_paths[i] + '</div>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add div_band\n",
+       "        div_string = '<div id = \\\"div_band' + i.toString() + '\\\" class = \\\"div_band\\\" ></div>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add div_dos\n",
+       "        div_string = '<div id = \\\"div_dos' + i.toString() + '\\\" class = \\\"div_dos\\\" ></div>';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add div_tools\n",
+       "        div_string = '<div id = \\\"div_tools' + i.toString() + '\\\" class = \\\"div_tools\\\" >';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add: infomation\n",
+       "        div_string = '<div id = \\\"div_info' + i.toString() + '\\\">atom_labels<br>program_name</div>';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add: custom scale\n",
+       "        div_string = '<br><p style=\\\"color: #000;font-weight: 100; font-size: 10pt; align:left\\\"> Set the lower and upper limit of energy scale (in eV): <br><br><font color=\\\"black\\\" size = 3px> Lower limit: &nbsp&nbsp </font><textarea  id=\\\"lowerlimit' + i.toString() + '\\\"  rows=\\\"1\\\" style = \\\"width: 70px;\\\">-10</textarea> <font color=\\\"black\\\" size = 3px> &nbsp eV</font> &nbsp&nbsp&nbsp<font color=\\\"black\\\" size = 3px> Upper limit: &nbsp&nbsp </font><textarea  id=\\\"upperlimit' + i.toString() + '\\\"  rows=\\\"1\\\" style = \\\"width: 70px;\\\">10</textarea> <font color=\\\"black\\\" size = 3px> &nbsp eV&nbsp&nbsp&nbsp</font></p>';\n",
+       "        table_content.push(div_string);\n",
+       "        div_string = '<br><button class = \\\"button_tools\\\" id = \\\"button_customscale' + i.toString() + '\\\"  onclick = \\\"customscale(this.id)\\\"> Rescale </button>';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "\n",
+       "        //add button:autoscale\n",
+       "        div_string = '<button class = \\\"button_tools\\\" id = \\\"button_autoscale' + i.toString() + '\\\"  onclick = \\\"autoscale(this.id)\\\" title = \\\"(-10 eV, 10 eV)\\\"> Autoscale </button>';    \n",
+       "        table_content.push(div_string);\n",
+       "        //add button:fullscale\n",
+       "        div_string = '<button class = \\\"button_tools\\\" id = \\\"button_fullscale' + i.toString() + '\\\"  onclick = \\\"fullscale(this.id)\\\" title = \\\"(-100 eV, 100 eV)\\\"> Full scale </button><br><br>';    \n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //table_content.push(\"Select and zoom:\");\n",
+       "\n",
+       "        /*//overview for select and zoom\n",
+       "        div_string = '<div id = \\\"div_overview' + i.toString() + '\\\" class = \\\"div_overview\\\" ></div>';    //  <div id=\"overview\" style=\"width:300px;height:200px; margin-left:10px; margin-top: 50px; padding-top: 0px\"></div>\n",
+       "        table_content.push(div_string);\n",
+       "        div_string = '<p id = \\\"overviewLegend' + i.toString() + '\\\"  ></p>';    //  <p id=\"overviewLegend\" style=\"margin-left:10px\"></p>\n",
+       "        table_content.push(div_string);*/\n",
+       "\n",
+       "        //download figures as png\n",
+       "        div_string = '<a id = \\\"img_band' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download band </a>';\n",
+       "        table_content.push(div_string);    \n",
+       "        div_string = '<a id = \\\"img_dos' + i.toString() + '\\\" class = \\\"button_tools\\\"  target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download DOS </a>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "        //add show VBM & CBM\n",
+       "        div_string = '<br><br><p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_VBM' + i.toString() + '\\\" unchecked  onclick=\\\"show_VBM(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Show VBM </font>  (<font color=\\\"blue\\\">\\•</font>) <font color=\\\"black\\\" size = 3px> and CBM </font>(<font color=\\\"red\\\">\\•</font>) </p>';\n",
+       "        table_content.push(div_string);\n",
+       "\n",
+       "\n",
+       "        table_content.push('</div>');//div_tools\n",
+       "\n",
+       "        //checkbox for comparison\n",
+       "        div_string = '<div id = \\\"div_checkbox_compare' + i.toString() + '\\\" class = \\\"div_checkbox_compare\\\" >';\n",
+       "        table_content.push(div_string);\n",
+       "        //div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n",
+       "        div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" checked = \\\"unchecked\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n",
+       "        table_content.push(div_string);\n",
+       "        table_content.push('</div>');//div_checkbox_compare\n",
+       "\n",
+       "\n",
+       "        table_content.push('</div>');//div_band_dos\n",
+       "        table_content.push('</th>');\n",
+       "        table_content.push('</tr>'); \n",
+       "      }\n",
+       "\n",
+       "      document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    function visualize_band_dos()\n",
+       "    {\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_jquery'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_axislabels'));\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_dashes'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_navigate'));\n",
+       "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_selection'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_flot_legendoncanvas'));\n",
+       "        document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n",
+       "        document.getElementById(\"div_compare_buttons\").style.visibility=\"\";\n",
+       "\n",
+       "\n",
+       "\n",
+       "        if(N_materials > N_max_show)\n",
+       "        {\n",
+       "            document.getElementById(\"div_showall\").style.visibility=\"visible\";\n",
+       "            document.getElementById(\"checkbox_showall\").checked = \"\";\n",
+       "        }              \n",
+       "\n",
+       "        N_materials_show = Math.min(N_max_show, N_materials);\n",
+       "\n",
+       "        prepare(N_materials_show);\n",
+       "        clean_compare_list();\n",
+       "        plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    function show_all(id)//\"plot_placeholder\"\n",
+       "    {\n",
+       "        var if_showall=0;\n",
+       "        if_showall = check_show_VBM(id);\n",
+       "        if(if_showall == 1)\n",
+       "        {\n",
+       "            N_materials_show = N_materials;\n",
+       "            prepare(N_materials_show);\n",
+       "            clean_compare_list();\n",
+       "            plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+       "        }\n",
+       "        else\n",
+       "        {\n",
+       "            N_materials_show = Math.min(N_max_show, N_materials);\n",
+       "            prepare(N_materials_show);\n",
+       "            clean_compare_list();\n",
+       "            plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+       "        }\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    \n",
+       "    //------------------Tool used to get the content from textarea---------------------\n",
+       "    function get_text(textarea_id)\n",
+       "    {\n",
+       "      var text = document.getElementById(textarea_id).value;\n",
+       "      return text;\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "\n",
+       "    //-------------------Compare 2 band figures----------------------------------------\n",
+       "\n",
+       "\n",
+       "    function check_compare(id)//checkbox_compare' + i.toString() + '\\\" unchecked  onclick=\\\"check_compare(this.id)\n",
+       "    {\n",
+       "      var x = document.getElementById(id);\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+       "      var N_chosen = 0;\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "      {\n",
+       "        if(choices_compare[i].checked)\n",
+       "        {\n",
+       "          N_chosen ++;\n",
+       "        }\n",
+       "      }\n",
+       "      if(N_chosen == 2) // In max. only 2 figures could be selected and compared.\n",
+       "      {\n",
+       "        for(var i=0; i<choices_compare.length; i++)\n",
+       "        {\n",
+       "          if(!choices_compare[i].checked)\n",
+       "          {\n",
+       "            choices_compare[i].disabled = 'disabled';\n",
+       "          }\n",
+       "        }\n",
+       "      }\n",
+       "      else\n",
+       "      {\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "        {\n",
+       "          choices_compare[i].removeAttribute('disabled');\n",
+       "        }\n",
+       "      }\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    function compare()\n",
+       "    {\n",
+       "        $(\"#div_compare\").fadeIn(600);//show div for comparison\n",
+       "        //check_compare(-100);\n",
+       "\n",
+       "        var compare_list = [];\n",
+       "        compare_list = make_compare_list();\n",
+       "                //[i_material_1, i_material_2] = make_compare_list();\n",
+       "        i_material_1 = compare_list[0];\n",
+       "        i_material_2 = compare_list[1];\n",
+       "        //document.getElementById(\"demo\").innerHTML = \"In add info compare:\" + i_material_1.toString() + i_material_2.toString();\n",
+       "        compare_figures(i_material_1, i_material_2);  \n",
+       "    }\n",
+       "    function make_compare_list()\n",
+       "    {\n",
+       "      //get the links to the images\n",
+       "      images_selected_links = []; //store the links to the figures for comparison\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+       "      var N_chosen = 0;\n",
+       "      var str = ''; //tmp str for debug\n",
+       "      var figure_selected = new Array(2);\n",
+       "      for(var i=0; i<choices_compare.length; i++) //check which figures are selected\n",
+       "      {\n",
+       "        if(choices_compare[i].checked)\n",
+       "        {\n",
+       "          id_chosen = choices_compare[i].id;\n",
+       "          i_chosen = Math.round(id_chosen.substring(16));\n",
+       "          var tmp_str = image_band_links[i_chosen];\n",
+       "          images_selected_links.push(tmp_str);\n",
+       "          figure_selected[N_chosen] = i_chosen;\n",
+       "          N_chosen ++;\n",
+       "          //str += beakerx.image_band_links[i];\n",
+       "        }\n",
+       "      }\n",
+       "      var i_material_1 = 0;\n",
+       "      var i_material_2 = 0;\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'In making comare list';\n",
+       "      image_band_links_selected = images_selected_links;\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'In making comare list: next';\n",
+       "      if(N_chosen == 2)\n",
+       "      {\n",
+       "        i_material_1 = figure_selected[0];\n",
+       "        i_material_2 = figure_selected[1];\n",
+       "      }\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'Compare_list: ' +i_material_1.toString() + ' ' + i_material_2.toString();\n",
+       "\n",
+       "      return [i_material_1, i_material_2];\n",
+       "    }\n",
+       "\n",
+       "    function check_compare_scale(i_material_1, i_material_2)\n",
+       "    {\n",
+       "      lowerlimit_id_1 = \"lowerlimit\" + i_material_1.toString();\n",
+       "      lowerlimit_id_2 = \"lowerlimit\" + i_material_2.toString();\n",
+       "      upperlimit_id_1 = \"upperlimit\" + i_material_1.toString();\n",
+       "      upperlimit_id_2 = \"upperlimit\" + i_material_2.toString();\n",
+       "\n",
+       "      lowerlimit_1 = parseFloat(document.getElementById(lowerlimit_id_1).innerHTML);\n",
+       "      lowerlimit_2 = parseFloat(document.getElementById(lowerlimit_id_2).innerHTML);\n",
+       "      upperlimit_1 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n",
+       "      upperlimit_2 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n",
+       "      if((lowerlimit_1 != lowerlimit_2) || (upperlimit_1 != upperlimit_2))\n",
+       "        return -1;\n",
+       "      else\n",
+       "        return 1;\n",
+       "    }\n",
+       "\n",
+       "    function compare_figures(i_material_1, i_material_2)\n",
+       "    {\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_query_beforeafter'));\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_compare_slide'));\n",
+       "        add_info_compare(i_material_1, i_material_2);\n",
+       "        document.getElementById(\"div_compare_container\").scrollIntoView({ behavior: 'smooth' }); \n",
+       "        document.getElementById(\"div_compare_container\").scrollTop += 50;\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    function clean_compare_list()\n",
+       "    {\n",
+       "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+       "      for(var i=0; i<choices_compare.length; i++)\n",
+       "      {\n",
+       "        //choices_compare[i].removeAttribute('checked');\n",
+       "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+       "        choices_compare[i].checked = \"\";\n",
+       "        choices_compare[i].removeAttribute('disabled');\n",
+       "      }\n",
+       "    }\n",
+       "\n",
+       "    //-----------Add information about the calculation to \"div_tools\"---------------\n",
+       "    function add_info(i)\n",
+       "    {\n",
+       "      \n",
+       "      //document.getElementById(\"demoa\").innerHTML = i.toString() + div_info_id;\n",
+       "      //for(var i = 0; i < beakerx.N_materials; i++)\n",
+       "      //{\n",
+       "      div_info_id = \"div_info\" + i.toString();\n",
+       "\n",
+       "      var str = '';\n",
+       "      str += \"<br> <p style=\\\"text-align:left\\\"><font size = 3pt><b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"atom_labels\"] + '</font></p>';\n",
+       "      //str += \"<font size = 3pt><b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"space_group_symbol\"] + '</font>';\n",
+       "      //str += \"<font size = 3pt><b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"lattice_constant\"] + '</font>';\n",
+       "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_name\"].toUpperCase() + '</font></p>';\n",
+       "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_basis_set_type\"] + '</font></p>';\n",
+       "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"XC_functional_name\"] + '</font></p>';\n",
+       "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3) + '</font></p>';\n",
+       "      document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n",
+       "      //document.getElementById('program_name_1').innerHTML = \"<b>Code:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"program_name\"];\n",
+       "      //document.getElementById('program_basis_set_type_1').innerHTML = \"<b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"program_basis_set_type\"];\n",
+       "      //document.getElementById('XC_functional_name_1').innerHTML = \"<b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"XC_functional_name\"];  \n",
+       "      //}\n",
+       "      \n",
+       "    }\n",
+       "    function add_info_compare(i,j)\n",
+       "    {\n",
+       "\n",
+       "      div_info_id = \"div_compare_info\";\n",
+       "      var str = '';\n",
+       "\n",
+       "      if_same_scale = check_compare_scale(i_material_1, i_material_2);\n",
+       "      if(if_same_scale == -1)\n",
+       "      {\n",
+       "        str = '<b><font size = \"15pt\" color=\"#940000\">Error: Different lower/upper limits.</font></b><br>';\n",
+       "        document.getElementById(\"div_compare_container\").innerHTML = str;\n",
+       "        document.getElementById(div_info_id).innerHTML = '';\n",
+       "        return;\n",
+       "      }\n",
+       "\n",
+       "      str += \"<br><b><font-size:15pt>Information of the first calculation (left):</font></b> <br>\";\n",
+       "      str += \"<br> <b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"atom_labels\"];\n",
+       "      //str += \"<br> <b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"space_group_symbol\"];\n",
+       "      //str += \"<br> <b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"lattice_constant\"];\n",
+       "      str += \"<br> <b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_name\"].toUpperCase();\n",
+       "      str += \"<br> <b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_basis_set_type\"];\n",
+       "      str += \"<br> <b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"XC_functional_name\"];\n",
+       "      str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+       "      str += \"<br><br><br><b><font-size:15pt>Information of the second calculation (right):</font></b><br>\";\n",
+       "      str += \"<br> <b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"atom_labels\"];\n",
+       "      //str += \"<br> <b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"space_group_symbol\"];\n",
+       "      //str += \"<br> <b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"lattice_constant\"];\n",
+       "      str += \"<br> <b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"program_name\"].toUpperCase();\n",
+       "      str += \"<br> <b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"program_basis_set_type\"];  \n",
+       "      str += \"<br> <b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"XC_functional_name\"];\n",
+       "      str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+       "      document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "\n",
+       "    //-----------------------Show/hide VBM, CBM-------------------------\n",
+       "    function check_show_VBM(checkbox_VBM_id)\n",
+       "    {\n",
+       "      var x = document.getElementById(checkbox_VBM_id);\n",
+       "      var if_checked = 0;\n",
+       "      if(x.checked)//== \"checked\")\n",
+       "      {\n",
+       "        //document.getElementById(\"demoa\").innerHTML = \"checked!\";\n",
+       "        if_checked = 1;\n",
+       "      }\n",
+       "      else if (x.unchecked)// == \"unchecked\")\n",
+       "      {\n",
+       "        //document.getElementById(\"demoa\").innerHTML = \"unchecked!\";\n",
+       "        if_checked = -1;\n",
+       "      }\n",
+       "      else\n",
+       "      {\n",
+       "        //document.getElementById(\"demoa\").innerHTML = \"nothing detected!\";\n",
+       "      }\n",
+       "      return if_checked;\n",
+       "    }\n",
+       "\n",
+       "    function check_if_in_compare_list(i) // check if the current material i is to be compared\n",
+       "    {\n",
+       "\n",
+       "      var checkbox_compare_id = \"checkbox_compare\" + i.toString();\n",
+       "      var if_compare = check_show_VBM(checkbox_compare_id);\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'if_compare of ' + i.toString() + ' : ' + if_compare.toString();\n",
+       "      var i_compare_material_1, i_compare_material_2;\n",
+       "      [i_compare_material_1, i_compare_material_2] = make_compare_list();\n",
+       "      var i_in_compare_list = -1;\n",
+       "      if(i_compare_material_1 == i)\n",
+       "      {\n",
+       "        i_in_compare_list = 1;\n",
+       "      }\n",
+       "      else if (i_compare_material_2 == i)\n",
+       "      {\n",
+       "        i_in_compare_list = 2;\n",
+       "      }\n",
+       "      else\n",
+       "      {\n",
+       "        i_in_compare_list = 0;\n",
+       "      }\n",
+       "      //document.getElementById(\"demo\").innerHTML = 'Checking ' + i.toString() + ' in Compare_list:  ' + i_in_compare_list.toString();\n",
+       "      return [if_compare, i_in_compare_list];\n",
+       "    }\n",
+       "\n",
+       "    function show_VBM(id)\n",
+       "    {\n",
+       "      //prepare(\"new\");\n",
+       "      //var if_show_VBM = -1;\n",
+       "      var len_id = id.length;\n",
+       "      var i_material = id.substring(12);\n",
+       "      var i = Math.round(i_material);\n",
+       "\n",
+       "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "\n",
+       "      var if_compare, i_in_compare_list;\n",
+       "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+       "      //document.getElementById(\"demo\").innerHTML = i.toString() + ' in Compare_list:  ' + i_in_compare_list.toString();\n",
+       "\n",
+       "      plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    //---------------------Functions to rescale-------------------------------------------\n",
+       "    function autoscale(id)\n",
+       "    {\n",
+       "      var len_id = id.length;\n",
+       "      var i_material = id.substring(16);\n",
+       "      var i = Math.round(i_material);\n",
+       "\n",
+       "      upperlim_id = \"upperlimit\" + i_material;\n",
+       "      document.getElementById(upperlim_id).innerHTML =\"10.0\";\n",
+       "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+       "      document.getElementById(lowerlim_id).innerHTML =\"-10.0\";\n",
+       "\n",
+       "\n",
+       "      //document.getElementById(\"demoa\").innerHTML =i_material;\n",
+       "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "\n",
+       "      var if_compare, i_in_compare_list;\n",
+       "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+       "\n",
+       "\n",
+       "      plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    function fullscale(id)\n",
+       "    {\n",
+       "      var len_id = id.length;\n",
+       "      var i_material = id.substring(16);\n",
+       "      var i = Math.round(i_material);\n",
+       "\n",
+       "      upperlim_id = \"upperlimit\" + i_material;\n",
+       "      document.getElementById(upperlim_id).innerHTML =\"100.0\";\n",
+       "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+       "      document.getElementById(lowerlim_id).innerHTML =\"-100.0\";\n",
+       "\n",
+       "      //document.getElementById(\"demoa\").innerHTML =i_material;\n",
+       "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "\n",
+       "      var if_compare, i_in_compare_list;\n",
+       "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+       "\n",
+       "\n",
+       "\n",
+       "      plot_band_dos_i(i, -100, 100, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "\n",
+       "    }\n",
+       "\n",
+       "    function customscale(id)\n",
+       "    {\n",
+       "      var len_id = id.length;\n",
+       "      var i_material = id.substring(18);\n",
+       "      var i = Math.round(i_material);\n",
+       "      //\n",
+       "      upperlim_id = \"upperlimit\" + i_material;\n",
+       "      upperlim = document.getElementById(upperlim_id).value;\n",
+       "      upperlim_float = Math.round(upperlim);\n",
+       "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+       "      lowerlim = document.getElementById(lowerlim_id).value;\n",
+       "      lowerlim_float = Math.round(lowerlim);\n",
+       "\n",
+       "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "\n",
+       "      var if_compare, i_in_compare_list;\n",
+       "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+       "\n",
+       "\n",
+       "\n",
+       "      plot_band_dos_i(i, lowerlim_float, upperlim_float, if_show_VBM, if_compare, i_in_compare_list);  \n",
+       "    }\n",
+       "\n",
+       "\n",
+       "    function plot_band_dos(lowerLim, upperLim, N_materials_show)\n",
+       "    {\n",
+       "      placeholder_band = \"#div_band1\";\n",
+       "      placeholder_dos = \"#div_dos1\";\n",
+       "     // lowerLim = -10.01\n",
+       "      //upperLim = 10.01\n",
+       "\n",
+       "\n",
+       "\n",
+       "      //alert(\"plot_band_dos\");\n",
+       "      //prepare();\n",
+       "      for(var i = 0; i < N_materials_show; i++)\n",
+       "      {\n",
+       "        \n",
+       "        var checkbox_material_id = \"checkbox_material\" + i.toString();\n",
+       "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+       "        if(if_selected != 1)\n",
+       "        {\n",
+       "          continue;\n",
+       "        }\n",
+       "        add_info(i);\n",
+       "      }\n",
+       "\n",
+       "      //------Plot----------------\n",
+       "        /*\n",
+       "      for(var i_material = 0; i_material < N_materials_show; i_material++)\n",
+       "      {\n",
+       "\n",
+       "        //alert(\"Material \"+i);\n",
+       "        var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n",
+       "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+       "        if(if_selected != 1)\n",
+       "        {\n",
+       "          continue;\n",
+       "        }\n",
+       "\n",
+       "        plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n",
+       "      }\n",
+       "        */\n",
+       "      //alert(\"next:for\")\n",
+       "      for (let i_material = 0, p = Promise.resolve(); i_material < N_materials_show; i_material++) {\n",
+       "        p = p.then(_ => new Promise(resolve =>\n",
+       "            setTimeout(function () {\n",
+       "                //alert(i_material)\n",
+       "                var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n",
+       "                var if_selected = check_show_VBM(checkbox_material_id);\n",
+       "                if(if_selected == 1)\n",
+       "                {\n",
+       "                    plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n",
+       "                }\n",
+       "                resolve();\n",
+       "            }, 0)\n",
+       "        ));\n",
+       "      }\n",
+       "\n",
+       "\n",
+       "      return 1;\n",
+       "    }\n",
+       "\n",
+       "    var i = 0\n",
+       "    var lowerLim = -10\n",
+       "    var upperLim = 10\n",
+       "    var if_show_VBM = 0\n",
+       "    var if_compare = 0\n",
+       "    var i_in_compare_list = -1\n",
+       "\n",
+       "\n",
+       "    \n",
+       "    function plot_band_dos_i(i_material, lowerLim_material, upperLim_material, if_show_VBM_material, if_compare_material, i_in_compare_list_material)\n",
+       "    {\n",
+       "        //alert(\"plot_band_dos_i\")\n",
+       "\n",
+       "        i = i_material;\n",
+       "        lowerLim = lowerLim_material;\n",
+       "        upperLim = upperLim_material;\n",
+       "        if_show_VBM = if_show_VBM_material;\n",
+       "        if_compare = if_compare_material;\n",
+       "        i_in_compare_list = i_in_compare_list_material;\n",
+       "        //alert(\"plot_band_dos_i: i_material: \"+i)\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_band'));\n",
+       "        //alert('i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list')\n",
+       "        //plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_dos'));\n",
+       "    }    \n",
+       "</script>\n",
+       "\n",
+       "                                \n",
+       "                                \n",
+       "<br><br>\n",
+       "<button  class=\"button\" onclick=\"process()\">Process data</button>\n",
+       "<br><br>\n",
+       "<div id = \"n_materials\" style = \"font-size: 18px; font-weight: 100; height: 60px; width: 100%;\"> Number of materials submitted: 0</div>\n",
+       "<div id = \"show_materials_submitted\" style = \"font-size: 20px; font-color: black;\"> </div>\n",
+       "\n",
+       "<div style = \"width :100%; height: 30px;\"></div> \n",
+       "<p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select materials to visualize the band structure and DOS:</p>\n",
+       "<div style = \"width :100%; height: 10px;\"></div> \n",
+       "<button class = \"button\" onclick = \"clean_materials_selection()\"> Clean selections </button> \n",
+       "<button class = \"button\" onclick = \"select_all()\"> Select all </button> \n",
+       "<button class = \"button\" onclick = \"visualize_band_dos()\"> Visualize </button> \n",
+       "<div style = \"width :100%; height: 30px;\"></div> \n",
+       "\n",
+       "<div id = \"show_materials_submitted_info\" style = \"width: 100%; font-size: 20px; font-color: black;\"> \n",
+       "  <table id = \"table_materials_submitted_info\" style=\"width:100%\"> </table>\n",
+       "</div>\n",
+       "\n",
+       "<div style = \"width :100%; height: 30px;\"></div> \n",
+       "\n",
+       "\n",
+       "\n",
+       "\n",
+       "<div id=\"div_compare_buttons\" style=\"visibility:hidden\">\n",
+       "  <br><br><br>\n",
+       "  <p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select two materials in the checkbox on the right for comparison:</p>\n",
+       "  <p style=\"color: #000;font-weight: 1000; font-size: 8pt;\"></p>\n",
+       "  <button class = \"button\" onclick = \"clean_compare_list()\"> Clean selections </button> \n",
+       "  <button class = \"button\" onclick = \"compare();compare()\" title = \"Select 2 materials in the checkbox below and compare: please make sure that the upper/lower limits are the same (using Rescale/Autoscale buttons).\" > Compare</button>\n",
+       "</div>\n",
+       "\n",
+       "\n",
+       "\n",
+       "<div id = \"div_showall\" style = \"width: 100%; visibility:hidden\">\n",
+       "  <div style = \"width: 100%; height: 30px; \"></div>\n",
+       "  <input type = \"checkbox\" id = \"checkbox_showall\" unchecked onclick=\"show_all(this.id)\"/> <font color=\"black\" size = 3px> Show all results </font><font size = 2px color = \"#666\"> (By default only the first 10 results are shown.) </font> \n",
+       "  <div style = \"width: 100%; height: 30px; \"></div>\n",
+       "</div>\n",
+       "\n",
+       "\n",
+       "\n",
+       "\n",
+       "\n",
+       "<div id = \"div_compare\" style = \"position: fixed; top: 20%; left: 10%; width: 1200px; height: 600px; z-index: 999999; border: 1px solid #555; background-color: #fff; display: none\" onclick = \"$(this).fadeOut(500)\"> \n",
+       "  \n",
+       "  <div style = \"float: right; width: 80px; height: 25px; margin-top: 10px; margin-right: 10px; z-index: 1000000; border: 1px solid #555; text-align: center; vertical-align: middle; background-color: #f9f9f9; font-size:12pt; font-color: #000; cursor:pointer;\" > CLOSE </div> <!--button to close the div-->\n",
+       "  <div id = \"div_compare_info\" style = \" width: 350px; height: 500px; float: right; margin-top: 50px; margin-right: 10px; z-index: 10000000;\"></div>\n",
+       "  <div id = \"div_compare_container\" style = \"margin-top: 50px; margin-left: 100px; width: 600px; height: 300px;\">\n",
+       "    <div class=\"g-before-after\" id = \"div_compare_containerx\"></div>\n",
+       "  </div>\n",
+       "</div>\n",
+       "\n",
+       "\n",
+       "<div id = \"demo\"></div>\n",
+       "\n",
+       "<div id = \"plot_placeholder\">\n",
+       "    <div><br></div>\n",
+       "    <table id = \"table_visualize\"> </table>\n",
+       "</div>\n",
+       "<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script>\n",
+    "    var N_max_show = 10; //Number of results to be shown by default\n",
+    "\n",
+    "    function show_materials_submitted_info()\n",
+    "    {\n",
+    "      //alert(\"N_materials=\" + N_materials)\n",
+    "      //\"table_materials_submitted_info\"\n",
+    "      //alert(\"show_materials_submitted_info: info_obj_all: \"+JSON.stringify(info_obj_all))\n",
+    "      var table_content = new Array(); \n",
+    "      str = '<tr>';\n",
+    "      str += '<th width=\"5%\"></th>'\n",
+    "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Atom labels</b></font></p></th>';\n",
+    "      //str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Space group</b></font></p></th>';\n",
+    "      //str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Lattice constants (in Ang)</b></font></p></th>';\n",
+    "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Program name</b></font></p></th>';\n",
+    "      str += '<th width=\"10%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Basis set type</b></font></p></th>';\n",
+    "      str += '<th width=\"15%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Functional</b></font></p></th>';\n",
+    "      //str += '<th width=\"20%\"><p style=\\\"text-align:center\\\"><font size = \\\"4pt\\\"><b>Number of <i>k</i> points per inverse distance</b></font></p></th>';\n",
+    "      str += '</tr>'; //first row: head\n",
+    "      table_content.push(str);\n",
+    "\n",
+    "      for(var i = 0; i < N_materials; i++) //add info of each material\n",
+    "      {\n",
+    "        //alert(\"show_materials_submitted_info: material \"+ i);  \n",
+    "        table_content.push('<tr>');\n",
+    "\n",
+    "        table_content.push('<td>');    \n",
+    "        str = '<input type = \\\"checkbox\\\" name = \"checkbox_material\" id = \\\"checkbox_material' + i.toString() + '\\\" unchecked  onclick=\\\"checkbox_material(this.id)\\\">';\n",
+    "        str += \"<b>&nbsp&nbsp#\" + (i+1).toString() + \"</b>\";\n",
+    "        table_content.push(str);\n",
+    "        table_content.push('</td>');\n",
+    "\n",
+    "        table_content.push('<td>');    \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"atom_labels\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got atom_labels\");\n",
+    "\n",
+    "        /*\n",
+    "        table_content.push('<td>');    \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"space_group_symbol\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got space_group_symbol\");\n",
+    "\n",
+    "        table_content.push('<td>');    \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"lattice_constant\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got lattice_constant\");\n",
+    "        */\n",
+    "          \n",
+    "        table_content.push('<td>'); \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"program_name\"].toUpperCase() + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got program_name\");\n",
+    "\n",
+    "        table_content.push('<td>'); \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"program_basis_set_type\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got program_basis_set_type\");\n",
+    "\n",
+    "\n",
+    "        table_content.push('<td>'); \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += info_obj_all[i][\"XC_functional_name\"] + '; &nbsp&nbsp';\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got XC_functional_name\");\n",
+    "\n",
+    "        /*\n",
+    "        table_content.push('<td>'); \n",
+    "        str = '<font size = \\\"3pt\\\">';\n",
+    "        str += band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+    "        str += \"</font>\"\n",
+    "        table_content.push(str);    \n",
+    "        table_content.push('</td>');\n",
+    "        //alert(\"got average_N_k_points_per_inverse_distance\");\n",
+    "        */\n",
+    "        table_content.push('</tr>');\n",
+    "\n",
+    "      }\n",
+    "      \n",
+    "      document.getElementById(\"table_materials_submitted_info\").innerHTML = table_content.join('');\n",
+    "    }\n",
+    "\n",
+    "    function clean_materials_selection()\n",
+    "    {\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_material\");\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "      {\n",
+    "        //choices_compare[i].removeAttribute('checked');\n",
+    "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+    "        choices_compare[i].checked = \"\";\n",
+    "      }\n",
+    "    }\n",
+    "\n",
+    "    function select_all()\n",
+    "    {\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_material\");\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "      {\n",
+    "        //choices_compare[i].removeAttribute('checked');\n",
+    "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+    "        choices_compare[i].checked = \"checked\";\n",
+    "      }\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "\n",
+    "    function process()\n",
+    "    {\n",
+    "        //alert(\"Process:\"+band_paths)\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_js_plot'));\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('show_materials_submitted_info'));\n",
+    "        show_materials_submitted_info();\n",
+    "        document.getElementById(\"table_visualize\").innerHTML = \"\";\n",
+    "        str = N_materials.toString();\n",
+    "        document.getElementById(\"n_materials\").innerHTML = \"Number of materials submitted: \" + str + \"<font size = 1px color = #C0C0C0  > &nbsp Please press \\'Visualize\\' to visualize the band structure. </font>\";\n",
+    "        document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n",
+    "    }\n",
+    "        \n",
+    "\n",
+    "    var image_band = '';\n",
+    "    var image_dos = '';\n",
+    "    var image_band_links = new Array(N_materials); //store the URL of each band figure -> used to compare 2 figures\n",
+    "    var image_band_links_selected = [];\n",
+    "    var image_band_selected_Number = []; //record which i_material has been selected\n",
+    "\n",
+    "\n",
+    "\n",
+    "    function prepare(N_materials_show)\n",
+    "    {\n",
+    "      document.getElementById(\"table_visualize\").innerHTML = \"\";\n",
+    "      var table_content = new Array(); \n",
+    "      //document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n",
+    "      //-----Generate the html tables for each material--------\n",
+    "      for(var i = 0; i < N_materials_show; i++)\n",
+    "      {\n",
+    "        checkbox_material_id = \"checkbox_material\" + i.toString();\n",
+    "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+    "        if(if_selected != 1)\n",
+    "        {\n",
+    "          continue;\n",
+    "        }\n",
+    "\n",
+    "        table_content.push('<tr>');\n",
+    "        div_string = '<div style = \\\"height: 20px\\\"></div>';\n",
+    "        table_content.push(div_string);\n",
+    "        table_content.push('<th>');\n",
+    "\n",
+    "        //add main container div\n",
+    "        div_string = '<div id = \\\"div_band_dos' + i.toString() + '\\\" class = \\\"div_band_dos\\\" >';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //show No. of the material\n",
+    "        i_material = i + 1;\n",
+    "        div_string = '<div style = \\\"height:30px\\; font-size: 15pt;\">' + '#' + i_material.toString() + '</div>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //show band_path/dos info\n",
+    "        div_string = '<div style = \\\"height:30px\\\">' + 'Band: &nbsp&nbsp' + band_paths[i] + ',&nbsp&nbsp&nbsp&nbspDOS: &nbsp&nbsp' + dos_paths[i] + '</div>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add div_band\n",
+    "        div_string = '<div id = \\\"div_band' + i.toString() + '\\\" class = \\\"div_band\\\" ></div>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add div_dos\n",
+    "        div_string = '<div id = \\\"div_dos' + i.toString() + '\\\" class = \\\"div_dos\\\" ></div>';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add div_tools\n",
+    "        div_string = '<div id = \\\"div_tools' + i.toString() + '\\\" class = \\\"div_tools\\\" >';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add: infomation\n",
+    "        div_string = '<div id = \\\"div_info' + i.toString() + '\\\">atom_labels<br>program_name</div>';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add: custom scale\n",
+    "        div_string = '<br><p style=\\\"color: #000;font-weight: 100; font-size: 10pt; align:left\\\"> Set the lower and upper limit of energy scale (in eV): <br><br><font color=\\\"black\\\" size = 3px> Lower limit: &nbsp&nbsp </font><textarea  id=\\\"lowerlimit' + i.toString() + '\\\"  rows=\\\"1\\\" style = \\\"width: 70px;\\\">-10</textarea> <font color=\\\"black\\\" size = 3px> &nbsp eV</font> &nbsp&nbsp&nbsp<font color=\\\"black\\\" size = 3px> Upper limit: &nbsp&nbsp </font><textarea  id=\\\"upperlimit' + i.toString() + '\\\"  rows=\\\"1\\\" style = \\\"width: 70px;\\\">10</textarea> <font color=\\\"black\\\" size = 3px> &nbsp eV&nbsp&nbsp&nbsp</font></p>';\n",
+    "        table_content.push(div_string);\n",
+    "        div_string = '<br><button class = \\\"button_tools\\\" id = \\\"button_customscale' + i.toString() + '\\\"  onclick = \\\"customscale(this.id)\\\"> Rescale </button>';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "\n",
+    "        //add button:autoscale\n",
+    "        div_string = '<button class = \\\"button_tools\\\" id = \\\"button_autoscale' + i.toString() + '\\\"  onclick = \\\"autoscale(this.id)\\\" title = \\\"(-10 eV, 10 eV)\\\"> Autoscale </button>';    \n",
+    "        table_content.push(div_string);\n",
+    "        //add button:fullscale\n",
+    "        div_string = '<button class = \\\"button_tools\\\" id = \\\"button_fullscale' + i.toString() + '\\\"  onclick = \\\"fullscale(this.id)\\\" title = \\\"(-100 eV, 100 eV)\\\"> Full scale </button><br><br>';    \n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //table_content.push(\"Select and zoom:\");\n",
+    "\n",
+    "        /*//overview for select and zoom\n",
+    "        div_string = '<div id = \\\"div_overview' + i.toString() + '\\\" class = \\\"div_overview\\\" ></div>';    //  <div id=\"overview\" style=\"width:300px;height:200px; margin-left:10px; margin-top: 50px; padding-top: 0px\"></div>\n",
+    "        table_content.push(div_string);\n",
+    "        div_string = '<p id = \\\"overviewLegend' + i.toString() + '\\\"  ></p>';    //  <p id=\"overviewLegend\" style=\"margin-left:10px\"></p>\n",
+    "        table_content.push(div_string);*/\n",
+    "\n",
+    "        //download figures as png\n",
+    "        div_string = '<a id = \\\"img_band' + i.toString() + '\\\" class = \\\"button_tools\\\" target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download band </a>';\n",
+    "        table_content.push(div_string);    \n",
+    "        div_string = '<a id = \\\"img_dos' + i.toString() + '\\\" class = \\\"button_tools\\\"  target=\\\"_blank\\\" style = \\\"text-decoration: none;\\\" > Download DOS </a>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "        //add show VBM & CBM\n",
+    "        div_string = '<br><br><p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_VBM' + i.toString() + '\\\" unchecked  onclick=\\\"show_VBM(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Show VBM </font>  (<font color=\\\"blue\\\">\\•</font>) <font color=\\\"black\\\" size = 3px> and CBM </font>(<font color=\\\"red\\\">\\•</font>) </p>';\n",
+    "        table_content.push(div_string);\n",
+    "\n",
+    "\n",
+    "        table_content.push('</div>');//div_tools\n",
+    "\n",
+    "        //checkbox for comparison\n",
+    "        div_string = '<div id = \\\"div_checkbox_compare' + i.toString() + '\\\" class = \\\"div_checkbox_compare\\\" >';\n",
+    "        table_content.push(div_string);\n",
+    "        //div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n",
+    "        div_string = '<p style = \\\"text-normal-black\\\"> <input type = \\\"checkbox\\\" id = \\\"checkbox_compare' + i.toString() + '\\\" checked = \\\"unchecked\\\" unchecked name = \\\"checkbox_compare\\\" onclick=\\\"check_compare(this.id)\\\"> <font color=\\\"black\\\" size = 3px> Compare </font></p><p><font size = 2px color = \"#666\">(select max. 2 materials) </font> </p>';\n",
+    "        table_content.push(div_string);\n",
+    "        table_content.push('</div>');//div_checkbox_compare\n",
+    "\n",
+    "\n",
+    "        table_content.push('</div>');//div_band_dos\n",
+    "        table_content.push('</th>');\n",
+    "        table_content.push('</tr>'); \n",
+    "      }\n",
+    "\n",
+    "      document.getElementById(\"table_visualize\").innerHTML = table_content.join('');\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    function visualize_band_dos()\n",
+    "    {\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_jquery'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_axislabels'));\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_dashes'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_navigate'));\n",
+    "        //Jupyter.notebook.execute_cells(window.findCellIndicesByTag('init_flot_selection'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_flot_legendoncanvas'));\n",
+    "        document.getElementById(\"div_showall\").style.visibility=\"hidden\";\n",
+    "        document.getElementById(\"div_compare_buttons\").style.visibility=\"\";\n",
+    "\n",
+    "\n",
+    "\n",
+    "        if(N_materials > N_max_show)\n",
+    "        {\n",
+    "            document.getElementById(\"div_showall\").style.visibility=\"visible\";\n",
+    "            document.getElementById(\"checkbox_showall\").checked = \"\";\n",
+    "        }              \n",
+    "\n",
+    "        N_materials_show = Math.min(N_max_show, N_materials);\n",
+    "\n",
+    "        prepare(N_materials_show);\n",
+    "        clean_compare_list();\n",
+    "        plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    function show_all(id)//\"plot_placeholder\"\n",
+    "    {\n",
+    "        var if_showall=0;\n",
+    "        if_showall = check_show_VBM(id);\n",
+    "        if(if_showall == 1)\n",
+    "        {\n",
+    "            N_materials_show = N_materials;\n",
+    "            prepare(N_materials_show);\n",
+    "            clean_compare_list();\n",
+    "            plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+    "        }\n",
+    "        else\n",
+    "        {\n",
+    "            N_materials_show = Math.min(N_max_show, N_materials);\n",
+    "            prepare(N_materials_show);\n",
+    "            clean_compare_list();\n",
+    "            plot_band_dos_status = plot_band_dos(-10,10, N_materials_show);\n",
+    "        }\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    \n",
+    "    //------------------Tool used to get the content from textarea---------------------\n",
+    "    function get_text(textarea_id)\n",
+    "    {\n",
+    "      var text = document.getElementById(textarea_id).value;\n",
+    "      return text;\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "\n",
+    "    //-------------------Compare 2 band figures----------------------------------------\n",
+    "\n",
+    "\n",
+    "    function check_compare(id)//checkbox_compare' + i.toString() + '\\\" unchecked  onclick=\\\"check_compare(this.id)\n",
+    "    {\n",
+    "      var x = document.getElementById(id);\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+    "      var N_chosen = 0;\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "      {\n",
+    "        if(choices_compare[i].checked)\n",
+    "        {\n",
+    "          N_chosen ++;\n",
+    "        }\n",
+    "      }\n",
+    "      if(N_chosen == 2) // In max. only 2 figures could be selected and compared.\n",
+    "      {\n",
+    "        for(var i=0; i<choices_compare.length; i++)\n",
+    "        {\n",
+    "          if(!choices_compare[i].checked)\n",
+    "          {\n",
+    "            choices_compare[i].disabled = 'disabled';\n",
+    "          }\n",
+    "        }\n",
+    "      }\n",
+    "      else\n",
+    "      {\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "        {\n",
+    "          choices_compare[i].removeAttribute('disabled');\n",
+    "        }\n",
+    "      }\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    function compare()\n",
+    "    {\n",
+    "        $(\"#div_compare\").fadeIn(600);//show div for comparison\n",
+    "        //check_compare(-100);\n",
+    "\n",
+    "        var compare_list = [];\n",
+    "        compare_list = make_compare_list();\n",
+    "                //[i_material_1, i_material_2] = make_compare_list();\n",
+    "        i_material_1 = compare_list[0];\n",
+    "        i_material_2 = compare_list[1];\n",
+    "        //document.getElementById(\"demo\").innerHTML = \"In add info compare:\" + i_material_1.toString() + i_material_2.toString();\n",
+    "        compare_figures(i_material_1, i_material_2);  \n",
+    "    }\n",
+    "    function make_compare_list()\n",
+    "    {\n",
+    "      //get the links to the images\n",
+    "      images_selected_links = []; //store the links to the figures for comparison\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+    "      var N_chosen = 0;\n",
+    "      var str = ''; //tmp str for debug\n",
+    "      var figure_selected = new Array(2);\n",
+    "      for(var i=0; i<choices_compare.length; i++) //check which figures are selected\n",
+    "      {\n",
+    "        if(choices_compare[i].checked)\n",
+    "        {\n",
+    "          id_chosen = choices_compare[i].id;\n",
+    "          i_chosen = Math.round(id_chosen.substring(16));\n",
+    "          var tmp_str = image_band_links[i_chosen];\n",
+    "          images_selected_links.push(tmp_str);\n",
+    "          figure_selected[N_chosen] = i_chosen;\n",
+    "          N_chosen ++;\n",
+    "          //str += beakerx.image_band_links[i];\n",
+    "        }\n",
+    "      }\n",
+    "      var i_material_1 = 0;\n",
+    "      var i_material_2 = 0;\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'In making comare list';\n",
+    "      image_band_links_selected = images_selected_links;\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'In making comare list: next';\n",
+    "      if(N_chosen == 2)\n",
+    "      {\n",
+    "        i_material_1 = figure_selected[0];\n",
+    "        i_material_2 = figure_selected[1];\n",
+    "      }\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'Compare_list: ' +i_material_1.toString() + ' ' + i_material_2.toString();\n",
+    "\n",
+    "      return [i_material_1, i_material_2];\n",
+    "    }\n",
+    "\n",
+    "    function check_compare_scale(i_material_1, i_material_2)\n",
+    "    {\n",
+    "      lowerlimit_id_1 = \"lowerlimit\" + i_material_1.toString();\n",
+    "      lowerlimit_id_2 = \"lowerlimit\" + i_material_2.toString();\n",
+    "      upperlimit_id_1 = \"upperlimit\" + i_material_1.toString();\n",
+    "      upperlimit_id_2 = \"upperlimit\" + i_material_2.toString();\n",
+    "\n",
+    "      lowerlimit_1 = parseFloat(document.getElementById(lowerlimit_id_1).innerHTML);\n",
+    "      lowerlimit_2 = parseFloat(document.getElementById(lowerlimit_id_2).innerHTML);\n",
+    "      upperlimit_1 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n",
+    "      upperlimit_2 = parseFloat(document.getElementById(upperlimit_id_2).innerHTML);\n",
+    "      if((lowerlimit_1 != lowerlimit_2) || (upperlimit_1 != upperlimit_2))\n",
+    "        return -1;\n",
+    "      else\n",
+    "        return 1;\n",
+    "    }\n",
+    "\n",
+    "    function compare_figures(i_material_1, i_material_2)\n",
+    "    {\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_query_beforeafter'));\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('js_compare_slide'));\n",
+    "        add_info_compare(i_material_1, i_material_2);\n",
+    "        document.getElementById(\"div_compare_container\").scrollIntoView({ behavior: 'smooth' }); \n",
+    "        document.getElementById(\"div_compare_container\").scrollTop += 50;\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    function clean_compare_list()\n",
+    "    {\n",
+    "      var choices_compare = document.getElementsByName(\"checkbox_compare\");\n",
+    "      for(var i=0; i<choices_compare.length; i++)\n",
+    "      {\n",
+    "        //choices_compare[i].removeAttribute('checked');\n",
+    "        //choices_compare[i].setAttribute(\"unchecked\", \"unchecked\");\n",
+    "        choices_compare[i].checked = \"\";\n",
+    "        choices_compare[i].removeAttribute('disabled');\n",
+    "      }\n",
+    "    }\n",
+    "\n",
+    "    //-----------Add information about the calculation to \"div_tools\"---------------\n",
+    "    function add_info(i)\n",
+    "    {\n",
+    "      \n",
+    "      //document.getElementById(\"demoa\").innerHTML = i.toString() + div_info_id;\n",
+    "      //for(var i = 0; i < beakerx.N_materials; i++)\n",
+    "      //{\n",
+    "      div_info_id = \"div_info\" + i.toString();\n",
+    "\n",
+    "      var str = '';\n",
+    "      str += \"<br> <p style=\\\"text-align:left\\\"><font size = 3pt><b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"atom_labels\"] + '</font></p>';\n",
+    "      //str += \"<font size = 3pt><b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"space_group_symbol\"] + '</font>';\n",
+    "      //str += \"<font size = 3pt><b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"lattice_constant\"] + '</font>';\n",
+    "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_name\"].toUpperCase() + '</font></p>';\n",
+    "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_basis_set_type\"] + '</font></p>';\n",
+    "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"XC_functional_name\"] + '</font></p>';\n",
+    "      str += \"<p style=\\\"text-align:left\\\"><font size = 3pt><b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[i][\"average_N_k_points_per_inverse_distance\"].toFixed(3) + '</font></p>';\n",
+    "      document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n",
+    "      //document.getElementById('program_name_1').innerHTML = \"<b>Code:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"program_name\"];\n",
+    "      //document.getElementById('program_basis_set_type_1').innerHTML = \"<b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"program_basis_set_type\"];\n",
+    "      //document.getElementById('XC_functional_name_1').innerHTML = \"<b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + origData[\"XC_functional_name\"];  \n",
+    "      //}\n",
+    "      \n",
+    "    }\n",
+    "    function add_info_compare(i,j)\n",
+    "    {\n",
+    "\n",
+    "      div_info_id = \"div_compare_info\";\n",
+    "      var str = '';\n",
+    "\n",
+    "      if_same_scale = check_compare_scale(i_material_1, i_material_2);\n",
+    "      if(if_same_scale == -1)\n",
+    "      {\n",
+    "        str = '<b><font size = \"15pt\" color=\"#940000\">Error: Different lower/upper limits.</font></b><br>';\n",
+    "        document.getElementById(\"div_compare_container\").innerHTML = str;\n",
+    "        document.getElementById(div_info_id).innerHTML = '';\n",
+    "        return;\n",
+    "      }\n",
+    "\n",
+    "      str += \"<br><b><font-size:15pt>Information of the first calculation (left):</font></b> <br>\";\n",
+    "      str += \"<br> <b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"atom_labels\"];\n",
+    "      //str += \"<br> <b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"space_group_symbol\"];\n",
+    "      //str += \"<br> <b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"lattice_constant\"];\n",
+    "      str += \"<br> <b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_name\"].toUpperCase();\n",
+    "      str += \"<br> <b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"program_basis_set_type\"];\n",
+    "      str += \"<br> <b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[i][\"XC_functional_name\"];\n",
+    "      str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+    "      str += \"<br><br><br><b><font-size:15pt>Information of the second calculation (right):</font></b><br>\";\n",
+    "      str += \"<br> <b>Atom labels:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"atom_labels\"];\n",
+    "      //str += \"<br> <b>Space group:</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"space_group_symbol\"];\n",
+    "      //str += \"<br> <b>Lattice constants (in Ang):</b> &nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"lattice_constant\"];\n",
+    "      str += \"<br> <b>Program name:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"program_name\"].toUpperCase();\n",
+    "      str += \"<br> <b>Basis set type:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"program_basis_set_type\"];  \n",
+    "      str += \"<br> <b>Functional:</b>&nbsp&nbsp&nbsp&nbsp\" + info_obj_all[j][\"XC_functional_name\"];\n",
+    "      str += \"<br> <b>Number of <i>k</i> points per inverse distance:</b>&nbsp&nbsp&nbsp&nbsp\" + band_obj_all[j][\"average_N_k_points_per_inverse_distance\"].toFixed(3);\n",
+    "      document.getElementById(div_info_id).innerHTML = str;// + origData[\"atom_labels\"];\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "\n",
+    "    //-----------------------Show/hide VBM, CBM-------------------------\n",
+    "    function check_show_VBM(checkbox_VBM_id)\n",
+    "    {\n",
+    "      var x = document.getElementById(checkbox_VBM_id);\n",
+    "      var if_checked = 0;\n",
+    "      if(x.checked)//== \"checked\")\n",
+    "      {\n",
+    "        //document.getElementById(\"demoa\").innerHTML = \"checked!\";\n",
+    "        if_checked = 1;\n",
+    "      }\n",
+    "      else if (x.unchecked)// == \"unchecked\")\n",
+    "      {\n",
+    "        //document.getElementById(\"demoa\").innerHTML = \"unchecked!\";\n",
+    "        if_checked = -1;\n",
+    "      }\n",
+    "      else\n",
+    "      {\n",
+    "        //document.getElementById(\"demoa\").innerHTML = \"nothing detected!\";\n",
+    "      }\n",
+    "      return if_checked;\n",
+    "    }\n",
+    "\n",
+    "    function check_if_in_compare_list(i) // check if the current material i is to be compared\n",
+    "    {\n",
+    "\n",
+    "      var checkbox_compare_id = \"checkbox_compare\" + i.toString();\n",
+    "      var if_compare = check_show_VBM(checkbox_compare_id);\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'if_compare of ' + i.toString() + ' : ' + if_compare.toString();\n",
+    "      var i_compare_material_1, i_compare_material_2;\n",
+    "      [i_compare_material_1, i_compare_material_2] = make_compare_list();\n",
+    "      var i_in_compare_list = -1;\n",
+    "      if(i_compare_material_1 == i)\n",
+    "      {\n",
+    "        i_in_compare_list = 1;\n",
+    "      }\n",
+    "      else if (i_compare_material_2 == i)\n",
+    "      {\n",
+    "        i_in_compare_list = 2;\n",
+    "      }\n",
+    "      else\n",
+    "      {\n",
+    "        i_in_compare_list = 0;\n",
+    "      }\n",
+    "      //document.getElementById(\"demo\").innerHTML = 'Checking ' + i.toString() + ' in Compare_list:  ' + i_in_compare_list.toString();\n",
+    "      return [if_compare, i_in_compare_list];\n",
+    "    }\n",
+    "\n",
+    "    function show_VBM(id)\n",
+    "    {\n",
+    "      //prepare(\"new\");\n",
+    "      //var if_show_VBM = -1;\n",
+    "      var len_id = id.length;\n",
+    "      var i_material = id.substring(12);\n",
+    "      var i = Math.round(i_material);\n",
+    "\n",
+    "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "\n",
+    "      var if_compare, i_in_compare_list;\n",
+    "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+    "      //document.getElementById(\"demo\").innerHTML = i.toString() + ' in Compare_list:  ' + i_in_compare_list.toString();\n",
+    "\n",
+    "      plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    //---------------------Functions to rescale-------------------------------------------\n",
+    "    function autoscale(id)\n",
+    "    {\n",
+    "      var len_id = id.length;\n",
+    "      var i_material = id.substring(16);\n",
+    "      var i = Math.round(i_material);\n",
+    "\n",
+    "      upperlim_id = \"upperlimit\" + i_material;\n",
+    "      document.getElementById(upperlim_id).innerHTML =\"10.0\";\n",
+    "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+    "      document.getElementById(lowerlim_id).innerHTML =\"-10.0\";\n",
+    "\n",
+    "\n",
+    "      //document.getElementById(\"demoa\").innerHTML =i_material;\n",
+    "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "\n",
+    "      var if_compare, i_in_compare_list;\n",
+    "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+    "\n",
+    "\n",
+    "      plot_band_dos_i(i, -10, 10, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    function fullscale(id)\n",
+    "    {\n",
+    "      var len_id = id.length;\n",
+    "      var i_material = id.substring(16);\n",
+    "      var i = Math.round(i_material);\n",
+    "\n",
+    "      upperlim_id = \"upperlimit\" + i_material;\n",
+    "      document.getElementById(upperlim_id).innerHTML =\"100.0\";\n",
+    "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+    "      document.getElementById(lowerlim_id).innerHTML =\"-100.0\";\n",
+    "\n",
+    "      //document.getElementById(\"demoa\").innerHTML =i_material;\n",
+    "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "\n",
+    "      var if_compare, i_in_compare_list;\n",
+    "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+    "\n",
+    "\n",
+    "\n",
+    "      plot_band_dos_i(i, -100, 100, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "\n",
+    "    }\n",
+    "\n",
+    "    function customscale(id)\n",
+    "    {\n",
+    "      var len_id = id.length;\n",
+    "      var i_material = id.substring(18);\n",
+    "      var i = Math.round(i_material);\n",
+    "      //\n",
+    "      upperlim_id = \"upperlimit\" + i_material;\n",
+    "      upperlim = document.getElementById(upperlim_id).value;\n",
+    "      upperlim_float = Math.round(upperlim);\n",
+    "      lowerlim_id = \"lowerlimit\" + i_material;\n",
+    "      lowerlim = document.getElementById(lowerlim_id).value;\n",
+    "      lowerlim_float = Math.round(lowerlim);\n",
+    "\n",
+    "      var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "      var if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "\n",
+    "      var if_compare, i_in_compare_list;\n",
+    "      [if_compare, i_in_compare_list] = check_if_in_compare_list(i);\n",
+    "\n",
+    "\n",
+    "\n",
+    "      plot_band_dos_i(i, lowerlim_float, upperlim_float, if_show_VBM, if_compare, i_in_compare_list);  \n",
+    "    }\n",
+    "\n",
+    "\n",
+    "    function plot_band_dos(lowerLim, upperLim, N_materials_show)\n",
+    "    {\n",
+    "      placeholder_band = \"#div_band1\";\n",
+    "      placeholder_dos = \"#div_dos1\";\n",
+    "     // lowerLim = -10.01\n",
+    "      //upperLim = 10.01\n",
+    "\n",
+    "\n",
+    "\n",
+    "      //alert(\"plot_band_dos\");\n",
+    "      //prepare();\n",
+    "      for(var i = 0; i < N_materials_show; i++)\n",
+    "      {\n",
+    "        \n",
+    "        var checkbox_material_id = \"checkbox_material\" + i.toString();\n",
+    "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+    "        if(if_selected != 1)\n",
+    "        {\n",
+    "          continue;\n",
+    "        }\n",
+    "        add_info(i);\n",
+    "      }\n",
+    "\n",
+    "      //------Plot----------------\n",
+    "        /*\n",
+    "      for(var i_material = 0; i_material < N_materials_show; i_material++)\n",
+    "      {\n",
+    "\n",
+    "        //alert(\"Material \"+i);\n",
+    "        var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n",
+    "        var if_selected = check_show_VBM(checkbox_material_id);\n",
+    "        if(if_selected != 1)\n",
+    "        {\n",
+    "          continue;\n",
+    "        }\n",
+    "\n",
+    "        plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n",
+    "      }\n",
+    "        */\n",
+    "      //alert(\"next:for\")\n",
+    "      for (let i_material = 0, p = Promise.resolve(); i_material < N_materials_show; i_material++) {\n",
+    "        p = p.then(_ => new Promise(resolve =>\n",
+    "            setTimeout(function () {\n",
+    "                //alert(i_material)\n",
+    "                var checkbox_material_id = \"checkbox_material\" + i_material.toString();\n",
+    "                var if_selected = check_show_VBM(checkbox_material_id);\n",
+    "                if(if_selected == 1)\n",
+    "                {\n",
+    "                    plot_band_dos_i(i_material, lowerLim, upperLim, 0, 0, -1);\n",
+    "                }\n",
+    "                resolve();\n",
+    "            }, 0)\n",
+    "        ));\n",
+    "      }\n",
+    "\n",
+    "\n",
+    "      return 1;\n",
+    "    }\n",
+    "\n",
+    "    var i = 0\n",
+    "    var lowerLim = -10\n",
+    "    var upperLim = 10\n",
+    "    var if_show_VBM = 0\n",
+    "    var if_compare = 0\n",
+    "    var i_in_compare_list = -1\n",
+    "\n",
+    "\n",
+    "    \n",
+    "    function plot_band_dos_i(i_material, lowerLim_material, upperLim_material, if_show_VBM_material, if_compare_material, i_in_compare_list_material)\n",
+    "    {\n",
+    "        //alert(\"plot_band_dos_i\")\n",
+    "\n",
+    "        i = i_material;\n",
+    "        lowerLim = lowerLim_material;\n",
+    "        upperLim = upperLim_material;\n",
+    "        if_show_VBM = if_show_VBM_material;\n",
+    "        if_compare = if_compare_material;\n",
+    "        i_in_compare_list = i_in_compare_list_material;\n",
+    "        //alert(\"plot_band_dos_i: i_material: \"+i)\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_band'));\n",
+    "        //alert('i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list')\n",
+    "        //plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "        Jupyter.notebook.execute_cells(window.findCellIndicesByTag('plot_dos'));\n",
+    "    }    \n",
+    "</script>\n",
+    "\n",
+    "                                \n",
+    "                                \n",
+    "<br><br>\n",
+    "<button  class=\"button\" onclick=\"process()\">Process data</button>\n",
+    "<br><br>\n",
+    "<div id = \"n_materials\" style = \"font-size: 18px; font-weight: 100; height: 60px; width: 100%;\"> Number of materials submitted: 0</div>\n",
+    "<div id = \"show_materials_submitted\" style = \"font-size: 20px; font-color: black;\"> </div>\n",
+    "\n",
+    "<div style = \"width :100%; height: 30px;\"></div> \n",
+    "<p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select materials to visualize the band structure and DOS:</p>\n",
+    "<div style = \"width :100%; height: 10px;\"></div> \n",
+    "<button class = \"button\" onclick = \"clean_materials_selection()\"> Clean selections </button> \n",
+    "<button class = \"button\" onclick = \"select_all()\"> Select all </button> \n",
+    "<button class = \"button\" onclick = \"visualize_band_dos()\"> Visualize </button> \n",
+    "<div style = \"width :100%; height: 30px;\"></div> \n",
+    "\n",
+    "<div id = \"show_materials_submitted_info\" style = \"width: 100%; font-size: 20px; font-color: black;\"> \n",
+    "  <table id = \"table_materials_submitted_info\" style=\"width:100%\"> </table>\n",
+    "</div>\n",
+    "\n",
+    "<div style = \"width :100%; height: 30px;\"></div> \n",
+    "\n",
+    "\n",
+    "\n",
+    "\n",
+    "<div id=\"div_compare_buttons\" style=\"visibility:hidden\">\n",
+    "  <br><br><br>\n",
+    "  <p style=\"color: #20335d;font-weight: 100; font-size: 18pt;\"> Select two materials in the checkbox on the right for comparison:</p>\n",
+    "  <p style=\"color: #000;font-weight: 1000; font-size: 8pt;\"></p>\n",
+    "  <button class = \"button\" onclick = \"clean_compare_list()\"> Clean selections </button> \n",
+    "  <button class = \"button\" onclick = \"compare();compare()\" title = \"Select 2 materials in the checkbox below and compare: please make sure that the upper/lower limits are the same (using Rescale/Autoscale buttons).\" > Compare</button>\n",
+    "</div>\n",
+    "\n",
+    "\n",
+    "\n",
+    "<div id = \"div_showall\" style = \"width: 100%; visibility:hidden\">\n",
+    "  <div style = \"width: 100%; height: 30px; \"></div>\n",
+    "  <input type = \"checkbox\" id = \"checkbox_showall\" unchecked onclick=\"show_all(this.id)\"/> <font color=\"black\" size = 3px> Show all results </font><font size = 2px color = \"#666\"> (By default only the first 10 results are shown.) </font> \n",
+    "  <div style = \"width: 100%; height: 30px; \"></div>\n",
+    "</div>\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n",
+    "<div id = \"div_compare\" style = \"position: fixed; top: 20%; left: 10%; width: 1200px; height: 600px; z-index: 999999; border: 1px solid #555; background-color: #fff; display: none\" onclick = \"$(this).fadeOut(500)\"> \n",
+    "  \n",
+    "  <div style = \"float: right; width: 80px; height: 25px; margin-top: 10px; margin-right: 10px; z-index: 1000000; border: 1px solid #555; text-align: center; vertical-align: middle; background-color: #f9f9f9; font-size:12pt; font-color: #000; cursor:pointer;\" > CLOSE </div> <!--button to close the div-->\n",
+    "  <div id = \"div_compare_info\" style = \" width: 350px; height: 500px; float: right; margin-top: 50px; margin-right: 10px; z-index: 10000000;\"></div>\n",
+    "  <div id = \"div_compare_container\" style = \"margin-top: 50px; margin-left: 100px; width: 600px; height: 300px;\">\n",
+    "    <div class=\"g-before-after\" id = \"div_compare_containerx\"></div>\n",
+    "  </div>\n",
+    "</div>\n",
+    "\n",
+    "\n",
+    "<div id = \"demo\"></div>\n",
+    "\n",
+    "<div id = \"plot_placeholder\">\n",
+    "    <div><br></div>\n",
+    "    <table id = \"table_visualize\"> </table>\n",
+    "</div>\n",
+    "<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {
+    "tags": [
+     "plot_band"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "        //alert(\"tag: plot_band\")\n",
+       "\n",
+       "plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n",
+       "\n",
+       "function plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n",
+       "{\n",
+       "        //i=0;\n",
+       "        //alert(\"plot_band \"+ i)\n",
+       "        var placeholder_band = \"#div_band\" + i.toString();\n",
+       "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+       "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+       "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+       "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+       "        var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+       "        var img_band_id = \"img_band\" + i.toString();\n",
+       "        var img_dos_id = \"img_dos\" + i.toString();\n",
+       "\n",
+       "        var placeholder_band_compare = \"\";\n",
+       "\n",
+       "\n",
+       "        if(i_in_compare_list == 1)\n",
+       "        {\n",
+       "            placeholder_band_compare = \"#div_band_compare_1\";\n",
+       "        }\n",
+       "        else if(i_in_compare_list == 2)\n",
+       "        {\n",
+       "            placeholder_band_compare = \"#div_band_compare_2\";\n",
+       "        }\n",
+       "        else\n",
+       "        {\n",
+       "            placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n",
+       "        }\n",
+       "\n",
+       "        Object.size = function(obj) {\n",
+       "            var size = 0, key;\n",
+       "            for (key in obj) \n",
+       "            {\n",
+       "                if (obj.hasOwnProperty(key)) size++;\n",
+       "            }\n",
+       "            return size;\n",
+       "        };\n",
+       "\n",
+       "        //Get the number of bands\n",
+       "        //alert(\"Getting band\")\n",
+       "        //alert(band_obj_all)\n",
+       "        //alert(\"band_obj_all got!\")\n",
+       "        var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n",
+       "        var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n",
+       "        //alert(band_obj_all[i][\"band_y_axis\"])\n",
+       "        var band_plotdata = [];\n",
+       "        \n",
+       "        for(var i_band =0; i_band < N_bands; i_band++)\n",
+       "        {\n",
+       "          var tmp_data = [];\n",
+       "          for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n",
+       "          {\n",
+       "            tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n",
+       "          }\n",
+       "          var plotData = { shadowSize: 0 , data: tmp_data, color: 'black',  series: { lines: { show: true } , points: {show: false} } };\n",
+       "          band_plotdata.push(plotData);\n",
+       "        }\n",
+       "\n",
+       "\n",
+       "        var tmp_data0 = [[0, 0], [1, 0]];\n",
+       "        var plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n",
+       "        band_plotdata.push(plotData0);\n",
+       "\n",
+       "        var band_plotdata_overview = band_plotdata.slice(0);\n",
+       "\n",
+       "        var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n",
+       "        var HOMOlabel = [\"VBM\"];\n",
+       "        var plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false},  showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+       "\n",
+       "        var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n",
+       "        var LUMOlabel = [\"CBM\"];\n",
+       "        var plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false},  showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+       "\n",
+       "        //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+       "        if (if_show_VBM == 1)\n",
+       "        {\n",
+       "          band_plotdata.push(plotHOMO);\n",
+       "          band_plotdata.push(plotLUMO);\n",
+       "        }\n",
+       "\n",
+       " \n",
+       "        //alert(img_band_id + band_plotdata)\n",
+       "            \n",
+       "        //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n",
+       "        //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\"  }\n",
+       "\n",
+       "        var canvas_band;\n",
+       "        var options_band = {\n",
+       "          canvas: true,\n",
+       "          //legend:{ type: \"canvas\" },\n",
+       "          series: { lines: { show: true, lineWidth: 2 }, \n",
+       "          points: { show: false } }, \n",
+       "          xaxis: { \n",
+       "            ticks: band_obj_all[i][\"labels\"], \n",
+       "            color:\"#000\", \n",
+       "            font: {size: 20}, \n",
+       "            zoomRange: false,\n",
+       "            panRange: false \n",
+       "          }, \n",
+       "          yaxis: { \n",
+       "            axisLabel: \"Energy (eV)\", \n",
+       "            axisLabelUseCanvas: true,\n",
+       "            //axisLabelUseCanvas: false,\n",
+       "            axisLabelFontSizePixels: 20,\n",
+       "            axisLabelFontFamily: 'Arial', \n",
+       "            axisLabelPadding: 10, \n",
+       "            color:\"#000\", \n",
+       "            font: {size: 20, family:\"Arial\"},\n",
+       "            tickLength:-5, \n",
+       "            min: lowerLim, \n",
+       "            max: upperLim,\n",
+       "            tickDecimals: 0, \n",
+       "            zoomRange: [0.001, 1000],\n",
+       "            panRange: [-100, 100] \n",
+       "          },\n",
+       "\n",
+       "          zoom: { \n",
+       "            interactive: true\n",
+       "          },\n",
+       "\n",
+       "          pan: {\n",
+       "            interactive: true\n",
+       "          }, \n",
+       "\n",
+       "          //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n",
+       "\n",
+       "          grid: { \n",
+       "            labelMargin: 15,\n",
+       "            hoverable: true, \n",
+       "            backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n",
+       "            borderWidth: {\n",
+       "              top: 2, \n",
+       "              right: 2,\n",
+       "              bottom: 2,\n",
+       "              left: 2,\n",
+       "              color : null } \n",
+       "          }\n",
+       "        }\n",
+       "        //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n",
+       "        //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n",
+       "        var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n",
+       "        var image_band = plot_band.toDataURL();\n",
+       "        image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n",
+       "        //beakerx.image_band = image_band;\n",
+       "        document.getElementById(img_band_id).href= image_band;\n",
+       "        image_band_links[i] = image_band;\n",
+       "        //alert(\"band done\")\n",
+       "}\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "        //alert(\"tag: plot_band\")\n",
+    "\n",
+    "plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list);\n",
+    "\n",
+    "function plot_band(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n",
+    "{\n",
+    "        //i=0;\n",
+    "        //alert(\"plot_band \"+ i)\n",
+    "        var placeholder_band = \"#div_band\" + i.toString();\n",
+    "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+    "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+    "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+    "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+    "        var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "        var img_band_id = \"img_band\" + i.toString();\n",
+    "        var img_dos_id = \"img_dos\" + i.toString();\n",
+    "\n",
+    "        var placeholder_band_compare = \"\";\n",
+    "\n",
+    "\n",
+    "        if(i_in_compare_list == 1)\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_1\";\n",
+    "        }\n",
+    "        else if(i_in_compare_list == 2)\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_2\";\n",
+    "        }\n",
+    "        else\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n",
+    "        }\n",
+    "\n",
+    "        Object.size = function(obj) {\n",
+    "            var size = 0, key;\n",
+    "            for (key in obj) \n",
+    "            {\n",
+    "                if (obj.hasOwnProperty(key)) size++;\n",
+    "            }\n",
+    "            return size;\n",
+    "        };\n",
+    "\n",
+    "        //Get the number of bands\n",
+    "        //alert(\"Getting band\")\n",
+    "        //alert(band_obj_all)\n",
+    "        //alert(\"band_obj_all got!\")\n",
+    "        var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n",
+    "        var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n",
+    "        //alert(band_obj_all[i][\"band_y_axis\"])\n",
+    "        var band_plotdata = [];\n",
+    "        \n",
+    "        for(var i_band =0; i_band < N_bands; i_band++)\n",
+    "        {\n",
+    "          var tmp_data = [];\n",
+    "          for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n",
+    "          {\n",
+    "            tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n",
+    "          }\n",
+    "          var plotData = { shadowSize: 0 , data: tmp_data, color: 'black',  series: { lines: { show: true } , points: {show: false} } };\n",
+    "          band_plotdata.push(plotData);\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        var tmp_data0 = [[0, 0], [1, 0]];\n",
+    "        var plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n",
+    "        band_plotdata.push(plotData0);\n",
+    "\n",
+    "        var band_plotdata_overview = band_plotdata.slice(0);\n",
+    "\n",
+    "        var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n",
+    "        var HOMOlabel = [\"VBM\"];\n",
+    "        var plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false},  showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+    "\n",
+    "        var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n",
+    "        var LUMOlabel = [\"CBM\"];\n",
+    "        var plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false},  showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+    "\n",
+    "        //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "        if (if_show_VBM == 1)\n",
+    "        {\n",
+    "          band_plotdata.push(plotHOMO);\n",
+    "          band_plotdata.push(plotLUMO);\n",
+    "        }\n",
+    "\n",
+    " \n",
+    "        //alert(img_band_id + band_plotdata)\n",
+    "            \n",
+    "        //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n",
+    "        //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\"  }\n",
+    "\n",
+    "        var canvas_band;\n",
+    "        var options_band = {\n",
+    "          canvas: true,\n",
+    "          //legend:{ type: \"canvas\" },\n",
+    "          series: { lines: { show: true, lineWidth: 2 }, \n",
+    "          points: { show: false } }, \n",
+    "          xaxis: { \n",
+    "            ticks: band_obj_all[i][\"labels\"], \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20}, \n",
+    "            zoomRange: false,\n",
+    "            panRange: false \n",
+    "          }, \n",
+    "          yaxis: { \n",
+    "            axisLabel: \"Energy (eV)\", \n",
+    "            axisLabelUseCanvas: true,\n",
+    "            //axisLabelUseCanvas: false,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial', \n",
+    "            axisLabelPadding: 10, \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20, family:\"Arial\"},\n",
+    "            tickLength:-5, \n",
+    "            min: lowerLim, \n",
+    "            max: upperLim,\n",
+    "            tickDecimals: 0, \n",
+    "            zoomRange: [0.001, 1000],\n",
+    "            panRange: [-100, 100] \n",
+    "          },\n",
+    "\n",
+    "          zoom: { \n",
+    "            interactive: true\n",
+    "          },\n",
+    "\n",
+    "          pan: {\n",
+    "            interactive: true\n",
+    "          }, \n",
+    "\n",
+    "          //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n",
+    "\n",
+    "          grid: { \n",
+    "            labelMargin: 15,\n",
+    "            hoverable: true, \n",
+    "            backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n",
+    "            borderWidth: {\n",
+    "              top: 2, \n",
+    "              right: 2,\n",
+    "              bottom: 2,\n",
+    "              left: 2,\n",
+    "              color : null } \n",
+    "          }\n",
+    "        }\n",
+    "        //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n",
+    "        //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n",
+    "        var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n",
+    "        var image_band = plot_band.toDataURL();\n",
+    "        image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n",
+    "        //beakerx.image_band = image_band;\n",
+    "        document.getElementById(img_band_id).href= image_band;\n",
+    "        image_band_links[i] = image_band;\n",
+    "        //alert(\"band done\")\n",
+    "}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {
+    "tags": [
+     "plot_dos"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "        //alert(\"tag: plot_dos \" + i)\n",
+       "        //i=0;\n",
+       "\n",
+       "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+       "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+       "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+       "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+       "        var img_dos_id = \"img_dos\" + i.toString();\n",
+       "\n",
+       "//----Plot DOS----------------------\n",
+       "        var dos_plotdata = [];\n",
+       "        //alert(\"dos:\"+dos_obj_all[i])\n",
+       "        var xdos = dos_obj_all[i][\"dos_x_axis\"];\n",
+       "        var ydos = dos_obj_all[i][\"dos_y_axis\"][0];\n",
+       "        var dosLabelPos = Math.max.apply(Math, ydos)/2;\n",
+       "        var d2 = [];\n",
+       "        for (var ii = 0; ii < xdos.length; ii+=1) {\n",
+       "          d2.push([ydos[ii],xdos[ii]]);\n",
+       "        }\n",
+       "        var plotData2={ shadowSize: 0, color: 'black' , data: d2};\n",
+       "        dos_plotdata.push(plotData2);\n",
+       "        //alert(\"dos_plotdata\"+JSON.stringify(dos_plotdata[0]));\n",
+       "        \n",
+       "        function find_xaxis_max_min(data, lowerbound, upperbound)\n",
+       "        {\n",
+       "                //data[xaxis,y] find the max and min value of x axis\n",
+       "                //alert(\"dos[0]:\" + data[0][\"data\"]);\n",
+       "                //alert(\"Bounds: \" + lowerbound + \" ,  \" + upperbound)\n",
+       "                var n_data = data.length;\n",
+       "                //alert(\"N dos: \" + n_data);\n",
+       "                var data_min = 1000000;\n",
+       "                var data_max = -1000000;\n",
+       "                var data_current = 0;\n",
+       "                for (var i = 0; i < n_data; i++)\n",
+       "                {\n",
+       "                    if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n",
+       "                    {\n",
+       "                        data_current = data[i][0];\n",
+       "                        //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n",
+       "                        if(data_current >= data_max)\n",
+       "                        {\n",
+       "                            data_max = data_current;\n",
+       "                        }\n",
+       "                        if(data_current <= data_min)\n",
+       "                        {\n",
+       "                            data_min = data_current;\n",
+       "                        }\n",
+       "                    }\n",
+       "                }\n",
+       "                var data_max_min = [data_max, data_min];\n",
+       "                //alert(\"data_max_min: \" + data_max_min);\n",
+       "                return data_max_min;\n",
+       "        }\n",
+       "        var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n",
+       "        var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n",
+       "        //alert(\"dos_x_max_min:\"+dos_x_max_min+\", dosLabelPos:\"+dosLabelPos);\n",
+       "        var options_dos ={\n",
+       "          canvas: true,\n",
+       "          series: {\n",
+       "            lines: { show: true, lineWidth:2 },\n",
+       "            points: { show: false }\n",
+       "          },\n",
+       "\n",
+       "          yaxis: { \n",
+       "            axisLabel: \"\", \n",
+       "            axisLabelUseCanvas: true,\n",
+       "            axisLabelFontSizePixels: 20,\n",
+       "            axisLabelFontFamily: 'Arial', \n",
+       "            axisLabelPadding: 10, \n",
+       "            color:\"#000\", \n",
+       "            font: {size: 20},\n",
+       "            tickLength:-5, \n",
+       "            min: lowerLim, \n",
+       "            max: upperLim,\n",
+       "            tickDecimals: 0, \n",
+       "            zoomRange: [0.001, 1000],\n",
+       "            panRange: [-100, 100] \n",
+       "          },\n",
+       "\n",
+       "          xaxis: {\n",
+       "            axisLabel: \" \",\n",
+       "            axisLabelUseCanvas: false,\n",
+       "            axisLabelFontSizePixels: 20,\n",
+       "            axisLabelFontFamily: 'Arial',\n",
+       "            axisLabelPadding: 3,\n",
+       "            color:\"rgb(0, 0, 0)\",\n",
+       "            font: {size: 20, family:\"Arial\"},\n",
+       "            //ticks: 10,\n",
+       "            tickLength:0,\n",
+       "            min: dos_x_max_min[1],//0,\n",
+       "            max: dos_x_max_min[0],//1,\n",
+       "            tickDecimals: 0,\n",
+       "            ticks: [[ dosLabelPos ,'DOS']],\n",
+       "            //tickFormatter: MyFormatter\n",
+       "            panRange: false\n",
+       "          },\n",
+       "          pan: {\n",
+       "            interactive: true\n",
+       "          }, \n",
+       "\n",
+       "          grid: {\n",
+       "            labelMargin: 15,\n",
+       "            hoverable: true,\n",
+       "            //borderWidth : 1000,\n",
+       "            //show : false,\n",
+       "            //  //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n",
+       "            backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n",
+       "            borderWidth: {\n",
+       "              top: 2,\n",
+       "              right: 2,\n",
+       "              bottom: 2,\n",
+       "              left: 2,\n",
+       "              color : null\n",
+       "            }\n",
+       "          }\n",
+       "        }\n",
+       "        var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n",
+       "        var image_dos = plot_dos.toDataURL();\n",
+       "        image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n",
+       "        image_dos = image_dos;\n",
+       "        document.getElementById(img_dos_id).href= image_dos;\n",
+       "        //alert(\"dos done.\")\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "        //alert(\"tag: plot_dos \" + i)\n",
+    "        //i=0;\n",
+    "\n",
+    "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+    "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+    "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+    "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+    "        var img_dos_id = \"img_dos\" + i.toString();\n",
+    "\n",
+    "//----Plot DOS----------------------\n",
+    "        var dos_plotdata = [];\n",
+    "        //alert(\"dos:\"+dos_obj_all[i])\n",
+    "        var xdos = dos_obj_all[i][\"dos_x_axis\"];\n",
+    "        var ydos = dos_obj_all[i][\"dos_y_axis\"][0];\n",
+    "        var dosLabelPos = Math.max.apply(Math, ydos)/2;\n",
+    "        var d2 = [];\n",
+    "        for (var ii = 0; ii < xdos.length; ii+=1) {\n",
+    "          d2.push([ydos[ii],xdos[ii]]);\n",
+    "        }\n",
+    "        var plotData2={ shadowSize: 0, color: 'black' , data: d2};\n",
+    "        dos_plotdata.push(plotData2);\n",
+    "        //alert(\"dos_plotdata\"+JSON.stringify(dos_plotdata[0]));\n",
+    "        \n",
+    "        function find_xaxis_max_min(data, lowerbound, upperbound)\n",
+    "        {\n",
+    "                //data[xaxis,y] find the max and min value of x axis\n",
+    "                //alert(\"dos[0]:\" + data[0][\"data\"]);\n",
+    "                //alert(\"Bounds: \" + lowerbound + \" ,  \" + upperbound)\n",
+    "                var n_data = data.length;\n",
+    "                //alert(\"N dos: \" + n_data);\n",
+    "                var data_min = 1000000;\n",
+    "                var data_max = -1000000;\n",
+    "                var data_current = 0;\n",
+    "                for (var i = 0; i < n_data; i++)\n",
+    "                {\n",
+    "                    if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n",
+    "                    {\n",
+    "                        data_current = data[i][0];\n",
+    "                        //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n",
+    "                        if(data_current >= data_max)\n",
+    "                        {\n",
+    "                            data_max = data_current;\n",
+    "                        }\n",
+    "                        if(data_current <= data_min)\n",
+    "                        {\n",
+    "                            data_min = data_current;\n",
+    "                        }\n",
+    "                    }\n",
+    "                }\n",
+    "                var data_max_min = [data_max, data_min];\n",
+    "                //alert(\"data_max_min: \" + data_max_min);\n",
+    "                return data_max_min;\n",
+    "        }\n",
+    "        var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n",
+    "        var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n",
+    "        //alert(\"dos_x_max_min:\"+dos_x_max_min+\", dosLabelPos:\"+dosLabelPos);\n",
+    "        var options_dos ={\n",
+    "          canvas: true,\n",
+    "          series: {\n",
+    "            lines: { show: true, lineWidth:2 },\n",
+    "            points: { show: false }\n",
+    "          },\n",
+    "\n",
+    "          yaxis: { \n",
+    "            axisLabel: \"\", \n",
+    "            axisLabelUseCanvas: true,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial', \n",
+    "            axisLabelPadding: 10, \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20},\n",
+    "            tickLength:-5, \n",
+    "            min: lowerLim, \n",
+    "            max: upperLim,\n",
+    "            tickDecimals: 0, \n",
+    "            zoomRange: [0.001, 1000],\n",
+    "            panRange: [-100, 100] \n",
+    "          },\n",
+    "\n",
+    "          xaxis: {\n",
+    "            axisLabel: \" \",\n",
+    "            axisLabelUseCanvas: false,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial',\n",
+    "            axisLabelPadding: 3,\n",
+    "            color:\"rgb(0, 0, 0)\",\n",
+    "            font: {size: 20, family:\"Arial\"},\n",
+    "            //ticks: 10,\n",
+    "            tickLength:0,\n",
+    "            min: dos_x_max_min[1],//0,\n",
+    "            max: dos_x_max_min[0],//1,\n",
+    "            tickDecimals: 0,\n",
+    "            ticks: [[ dosLabelPos ,'DOS']],\n",
+    "            //tickFormatter: MyFormatter\n",
+    "            panRange: false\n",
+    "          },\n",
+    "          pan: {\n",
+    "            interactive: true\n",
+    "          }, \n",
+    "\n",
+    "          grid: {\n",
+    "            labelMargin: 15,\n",
+    "            hoverable: true,\n",
+    "            //borderWidth : 1000,\n",
+    "            //show : false,\n",
+    "            //  //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n",
+    "            backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n",
+    "            borderWidth: {\n",
+    "              top: 2,\n",
+    "              right: 2,\n",
+    "              bottom: 2,\n",
+    "              left: 2,\n",
+    "              color : null\n",
+    "            }\n",
+    "          }\n",
+    "        }\n",
+    "        var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n",
+    "        var image_dos = plot_dos.toDataURL();\n",
+    "        image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n",
+    "        image_dos = image_dos;\n",
+    "        document.getElementById(img_dos_id).href= image_dos;\n",
+    "        //alert(\"dos done.\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {
+    "tags": [
+     "init_jquery"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"http://code.jquery.com/jquery-1.8.3.min.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"http://code.jquery.com/jquery-1.8.3.min.js\"></script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {
+    "tags": [
+     "init_flot"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"js/jquery.flot.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"js/jquery.flot.js\"></script>\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {
+    "tags": [
+     "init_flot_axislabels"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"js/jquery.flot.axislabels.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"js/jquery.flot.axislabels.js\"></script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {
+    "tags": [
+     "init_flot_navigate"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"js/jquery.flot.navigate.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"js/jquery.flot.navigate.js\"></script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 87,
+   "metadata": {
+    "tags": [
+     "init_flot_selection"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<script src=\"js/jquery.flot.selection.js\"></script>\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.HTML object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%HTML\n",
+    "<script src=\"js/jquery.flot.selection.js\"></script>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 51,
+   "metadata": {
+    "tags": [
+     "js_query_beforeafter"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "//jquery.beforeafter.min.js\n",
+       "!function(e){e.fn.beforeafter=function(i){var t=e.extend({touch:!0,message:\"Slide\",hide_message:!0,reset:!0,reset_delay:3e3,drag_horizontal:!0,split_horizontal:!0\n",
+       "},i);return this.each(function(){var i=e(this),a=i.find(\"img\"),n=a.data(\"aftersrc\"),s=i.width(),d=0;a.after('<div class=\"g-img-after\"><img style=\"width: '+s+'px;\" src=\"'+n+'\"></div>'),\n",
+       "a.addClass(\"g-img-before\").width(s),i.append('<div class=\"g-img-divider\"><span>'+t.message+\"</span></div>\"),d=i.height(),t.split_horizontal||i.addClass(\"g-vertical\"),\n",
+       "i.on(\"mouseenter touchstart\",function(e){var t=i.data(\"reset-timer\");t&&(window.clearTimeout(t),i.data(\"reset-timer\",!1))}).on(\"mousemove touchmove\",function(a){\n",
+       "var n=0,o=0,r=i.find(\".g-img-divider span\");if(t.drag_horizontal)n=a.pageX-i.offset().left,o=n/s*100;else{var f=i.offset().top-e(window).scrollTop();n=a.clientY/f,\n",
+       "o=(a.clientY-f)/d*100}if(t.touch&&\"undefined\"!=typeof a.originalEvent.touches){var g=a.originalEvent.touches[0];o=t.drag_horizontal?(g.pageX-i.offset().left)/s*100:(g.pageY-i.offset().top)/d*100;\n",
+       "}t.split_horizontal?(i.find(\".g-img-after\").css(\"left\",o+\"%\"),i.find(\".g-img-divider\").css(\"left\",o+\"%\")):(i.find(\".g-img-after\").css(\"top\",o+\"%\"),i.find(\".g-img-divider\").css(\"top\",o+\"%\")),\n",
+       "t.hide_message&&r.is(\":visible\")&&r.fadeOut()}).on(\"mouseleave touchend touchcancel\",function(e){var a=i.data(\"reset-timer\"),n=i.find(\".g-img-divider span\");\n",
+       "t.reset&&(a||(a=window.setTimeout(function(){t.split_horizontal?(i.find(\".g-img-after\").animate({left:\"50%\"},500),i.find(\".g-img-divider\").animate({left:\"50%\"\n",
+       "},500,function(){n.fadeIn()})):(i.find(\".g-img-after\").animate({top:\"50%\"},500),i.find(\".g-img-divider\").animate({top:\"50%\"},500,function(){n.fadeIn()})),\n",
+       "i.data(\"reset-timer\",!1)},t.reset_delay),i.data(\"reset-timer\",a)))})}),this}}(jQuery);\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "//jquery.beforeafter.min.js\n",
+    "!function(e){e.fn.beforeafter=function(i){var t=e.extend({touch:!0,message:\"Slide\",hide_message:!0,reset:!0,reset_delay:3e3,drag_horizontal:!0,split_horizontal:!0\n",
+    "},i);return this.each(function(){var i=e(this),a=i.find(\"img\"),n=a.data(\"aftersrc\"),s=i.width(),d=0;a.after('<div class=\"g-img-after\"><img style=\"width: '+s+'px;\" src=\"'+n+'\"></div>'),\n",
+    "a.addClass(\"g-img-before\").width(s),i.append('<div class=\"g-img-divider\"><span>'+t.message+\"</span></div>\"),d=i.height(),t.split_horizontal||i.addClass(\"g-vertical\"),\n",
+    "i.on(\"mouseenter touchstart\",function(e){var t=i.data(\"reset-timer\");t&&(window.clearTimeout(t),i.data(\"reset-timer\",!1))}).on(\"mousemove touchmove\",function(a){\n",
+    "var n=0,o=0,r=i.find(\".g-img-divider span\");if(t.drag_horizontal)n=a.pageX-i.offset().left,o=n/s*100;else{var f=i.offset().top-e(window).scrollTop();n=a.clientY/f,\n",
+    "o=(a.clientY-f)/d*100}if(t.touch&&\"undefined\"!=typeof a.originalEvent.touches){var g=a.originalEvent.touches[0];o=t.drag_horizontal?(g.pageX-i.offset().left)/s*100:(g.pageY-i.offset().top)/d*100;\n",
+    "}t.split_horizontal?(i.find(\".g-img-after\").css(\"left\",o+\"%\"),i.find(\".g-img-divider\").css(\"left\",o+\"%\")):(i.find(\".g-img-after\").css(\"top\",o+\"%\"),i.find(\".g-img-divider\").css(\"top\",o+\"%\")),\n",
+    "t.hide_message&&r.is(\":visible\")&&r.fadeOut()}).on(\"mouseleave touchend touchcancel\",function(e){var a=i.data(\"reset-timer\"),n=i.find(\".g-img-divider span\");\n",
+    "t.reset&&(a||(a=window.setTimeout(function(){t.split_horizontal?(i.find(\".g-img-after\").animate({left:\"50%\"},500),i.find(\".g-img-divider\").animate({left:\"50%\"\n",
+    "},500,function(){n.fadeIn()})):(i.find(\".g-img-after\").animate({top:\"50%\"},500),i.find(\".g-img-divider\").animate({top:\"50%\"},500,function(){n.fadeIn()})),\n",
+    "i.data(\"reset-timer\",!1)},t.reset_delay),i.data(\"reset-timer\",a)))})}),this}}(jQuery);"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 52,
+   "metadata": {
+    "tags": [
+     "js_compare_slide"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "var div_str = '';\n",
+       "//div_str = '<style>  .g-before-after{position:relative;overflow:hidden}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%} </style>'\n",
+       "//div_str += '<script>$(\\'#div_compare_containerx\\').beforeafter();  </script>';\n",
+       "//div_str +='<script type=\\\"text/javascript\\\" src=\\\"https://github.com/jquery/jquery/blob/master/src/jquery.js\\\"></script> '\n",
+       "//div_str += '<div class=\\\"g-before-after\\\" id=\\\"div_compare_containerx\\\">';\n",
+       "div_str +='<img src = \\\"'\n",
+       "\n",
+       "var src1 = image_band_links_selected[0];\n",
+       "var src2 = image_band_links_selected[1];\n",
+       "var tmp_src1 = src1;\n",
+       "var tmp_src2 = src2;\n",
+       "//src1 = \"https://images4.alphacoders.com/640/640956.jpg\";\n",
+       "//src2 = \"http://imgmr.com/wp-content/uploads/2016/06/SAO-anime.jpg\";\n",
+       "div_str +=src1;\n",
+       "div_str += '\\\" data-aftersrc=\\\"'\n",
+       "div_str +=src2;\n",
+       "//div_str += '\\\"></div>';\n",
+       "div_str += '\\\"/>';\n",
+       "//#div_compare_containerx\n",
+       "document.getElementById(\"div_compare_containerx\").innerHTML = div_str;\n",
+       "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n",
+       "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n",
+       "//beakerx.image_band_links[i]\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "var div_str = '';\n",
+    "//div_str = '<style>  .g-before-after{position:relative;overflow:hidden}.g-before-after img{display:block}.g-before-after .g-img-before{float:left}.g-before-after .g-img-after,.g-before-after.g-vertical .g-img-after{position:absolute;top:0;right:0;left:50%;bottom:0;overflow:hidden}.g-before-after .g-img-after img{position:absolute;right:0;top:0}.g-before-after .g-img-divider{position:absolute;left:50%;top:0;bottom:0;width:0;border-left:1px solid #fff;border-right:1px solid #fff}.g-before-after .g-img-divider>span{position:absolute;top:50%;display:block;background-color:#fff;padding:5px 10px;line-height:1;text-align:center;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.g-before-after.g-vertical .g-img-after{top:50%;left:0}.g-before-after.g-vertical .g-img-after img{position:absolute;right:auto;top:auto;left:0;bottom:0}.g-before-after.g-vertical .g-img-divider{position:absolute;left:0;top:50%;bottom:auto;right:0;height:0;width:100%;border-top:1px solid #fff;border-bottom:1px solid #fff;border-left:0 none;border-right:0 none}.g-before-after.g-vertical .g-img-divider>span{top:50%;left:50%} </style>'\n",
+    "//div_str += '<script>$(\\'#div_compare_containerx\\').beforeafter();  </script>';\n",
+    "//div_str +='<script type=\\\"text/javascript\\\" src=\\\"https://github.com/jquery/jquery/blob/master/src/jquery.js\\\"></script> '\n",
+    "//div_str += '<div class=\\\"g-before-after\\\" id=\\\"div_compare_containerx\\\">';\n",
+    "div_str +='<img src = \\\"'\n",
+    "\n",
+    "var src1 = image_band_links_selected[0];\n",
+    "var src2 = image_band_links_selected[1];\n",
+    "var tmp_src1 = src1;\n",
+    "var tmp_src2 = src2;\n",
+    "//src1 = \"https://images4.alphacoders.com/640/640956.jpg\";\n",
+    "//src2 = \"http://imgmr.com/wp-content/uploads/2016/06/SAO-anime.jpg\";\n",
+    "div_str +=src1;\n",
+    "div_str += '\\\" data-aftersrc=\\\"'\n",
+    "div_str +=src2;\n",
+    "//div_str += '\\\"></div>';\n",
+    "div_str += '\\\"/>';\n",
+    "//#div_compare_containerx\n",
+    "document.getElementById(\"div_compare_containerx\").innerHTML = div_str;\n",
+    "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n",
+    "$('#div_compare_containerx').beforeafter({drag_horizontal: false, split_horizontal: false});\n",
+    "//beakerx.image_band_links[i]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "scrolled": false,
+    "tags": [
+     "process_band_dos_data_python"
+    ]
+   },
+   "outputs": [],
+   "source": [
+    "#tag:python_2\n",
+    "import urllib.request, json\n",
+    "import numpy as np\n",
+    "import math\n",
+    "\n",
+    "#======Define global objs============\n",
+    "info_all = []\n",
+    "band_obj_all = []\n",
+    "dos_obj_all = []\n",
+    "\n",
+    "def load_jsonfile(path):\n",
+    "    #with open(path, encoding='utf-8') as band_file:    \n",
+    "    #    return json.load(band_file)\n",
+    "\n",
+    " \n",
+    "    with urllib.request.urlopen(path) as url:\n",
+    "        data = json.loads(url.read().decode())\n",
+    "    return data\n",
+    "\n",
+    "#-----Get the labels for x axis---------------\n",
+    "def get_label_flag(coor_array):\n",
+    "    #np.sort(coor_array)\n",
+    "    x = coor_array[0]\n",
+    "    y = coor_array[1]\n",
+    "    z = coor_array[2]\n",
+    "    coor =np.sort([x,y,z])\n",
+    "    xx = coor[0]\n",
+    "    yy = coor[1]\n",
+    "    zz = coor[2]\n",
+    "    coor = [xx, yy, zz]\n",
+    "    #pprint(coor)\n",
+    "    if (coor == [0, 0.5, 0.5]):\n",
+    "        return \"X\"\n",
+    "    if (coor == [0, 0.0, 0.5]):\n",
+    "        return \"M\"\n",
+    "    elif (coor == [0.5, 0.5, 0.5]):\n",
+    "        return \"L\"\n",
+    "    elif (coor == [0.375, 0.375, 0.75]):\n",
+    "        return \"K\"\n",
+    "    elif (coor == [0.25, 0.5, 0.75]):\n",
+    "        return \"W\"\n",
+    "    elif (coor == [0, 0, 0]):\n",
+    "        return \"\\u0393\"\n",
+    "    elif (coor == [0.25, 0.625, 0.625]):\n",
+    "        return \"U\"\n",
+    "    else:\n",
+    "        return \"?\"\n",
+    "\n",
+    "#============Process the band structure data============\n",
+    "def get_band_obj(band_path, dos_fermi_energy):\n",
+    "\n",
+    "    #band_data: read from json file    \n",
+    "    #Load the data files for band\n",
+    "    band_data = load_jsonfile(band_path)\n",
+    "   \n",
+    "    #---------Read section_k_band_segment------------\n",
+    "    section_k_band_segment = band_data['section_run']['section_single_configuration_calculation']['section_k_band'][0]['section_k_band_segment']\n",
+    "    \n",
+    "    #--------Get the number of k band segments-------------\n",
+    "    N_k_band_segments = len(section_k_band_segment)\n",
+    "    \n",
+    "    #----------Get the total number of k points in all segments---------\n",
+    "    N_k_points_all = 0\n",
+    "    for i in range(N_k_band_segments):\n",
+    "        band_k_points = section_k_band_segment[i]['band_k_points']\n",
+    "        N_k_points_all = N_k_points_all + len(band_k_points)\n",
+    "    \n",
+    "    #--------Get the x axis for the band structure figure: the coordinates of k points in 1D\n",
+    "    # store in k_coor_1D[N_k_points_total]-----------------\n",
+    "\n",
+    "    band_distance_segments = np.zeros(N_k_band_segments)\n",
+    "    for i in range(N_k_band_segments):\n",
+    "        [[x1, y1, z1],[x2, y2, z2]]= section_k_band_segment[i]['band_segm_start_end']  #\"band_segm_start_end\": [[0.5, 0.0, 0.5],[0.5, 0.25, 0.75]],\n",
+    "        band_distance_segments[i] = math.pow((x1-x2), 2) + math.pow((y1-y2), 2) + math.pow((z1-z2), 2)\n",
+    "\n",
+    "    \n",
+    "    band_distance_total = math.fsum(band_distance_segments)\n",
+    "    #print(band_distance_segments)\n",
+    "    average_N_k_points_per_inverse_distance = N_k_points_all / band_distance_total\n",
+    "    \n",
+    "    #Prepare the parameters to rescale the k coordinates into [0,1]\n",
+    "    step_k_point = 1.0 / N_k_points_all\n",
+    "    step_k_point = (1.0 + step_k_point) / N_k_points_all\n",
+    "    \n",
+    "    #   \n",
+    "    k_coor_1D = np.zeros((N_k_points_all))\n",
+    "    for i_k_points in range(N_k_points_all):\n",
+    "        k_coor_1D[i_k_points] = round( step_k_point * i_k_points, 3)\n",
+    "    #for i in range(N_k_band_segments):\n",
+    "    #    ki[i] = \n",
+    "    \n",
+    "\n",
+    "    #--------Get the eigenvalues of each band trajectory--------------\n",
+    "    N_k_points_per_segment = len(section_k_band_segment[0]['band_energies'][0]) #suppose the numebr of k points in all the segments are the same\n",
+    "    N_bands = len(section_k_band_segment[0]['band_energies'][0][0])\n",
+    "    band_energies_all = np.zeros((N_bands, N_k_points_all)) #store the eigenvalues\n",
+    "    N_k_points_all = 0\n",
+    "    for i_segments in range(N_k_band_segments):\n",
+    "        band_energies = section_k_band_segment[i_segments]['band_energies']\n",
+    "        N_spin_channel = len(band_energies) #Number of the spin channel --FIXME: no spin polarized\n",
+    "        N_k_points_per_segment = len(band_energies[0])\n",
+    "        for i_k_points in range(N_k_points_per_segment):\n",
+    "            for i_bands in range(N_bands):\n",
+    "                band_energies_all[i_bands][N_k_points_all] = band_energies[0][i_k_points][i_bands] / (1.60217656535 * pow(10, -19))\n",
+    "            N_k_points_all = N_k_points_all + 1\n",
+    "    \n",
+    "    \n",
+    "    N_labels = 0\n",
+    "    for i_segments in range(N_k_band_segments):\n",
+    "        for j in range(2):\n",
+    "            labels_tmp =  section_k_band_segment[i_segments]['band_segm_start_end'][j];\n",
+    "            N_labels = N_labels + 1\n",
+    "\n",
+    "    label_flag = [\"\" for i in range(N_labels)] #stores the flags of the labels (X, W, G, etc)\n",
+    "\n",
+    "    i_label = 0\n",
+    "    label_flag_last_final = \"\"\n",
+    "    label_flag_current_initial = \"\"\n",
+    "    for i_segments in range(N_k_band_segments):\n",
+    "        labels_coor_0 =  section_k_band_segment[i_segments]['band_segm_start_end'][0];\n",
+    "        labels_coor_1 =  section_k_band_segment[i_segments]['band_segm_start_end'][1];\n",
+    "        np.sort(labels_coor_0)\n",
+    "        np.sort(labels_coor_1)\n",
+    "        label_flag_0 = get_label_flag(labels_coor_0)\n",
+    "        label_flag_1 = get_label_flag(labels_coor_1)\n",
+    "        label_flag_current_initial = label_flag_0\n",
+    "        if(label_flag_last_final == \"\"):\n",
+    "            label_flag_last_final = label_flag_0\n",
+    "\n",
+    "        if(label_flag_last_final == label_flag_current_initial):\n",
+    "            label_flag[i_label] = label_flag_current_initial\n",
+    "        else:\n",
+    "            label_flag[i_label] = \"\".join([label_flag_last_final, '|', label_flag_current_initial])\n",
+    "        label_flag_last_final = label_flag_1\n",
+    "    \n",
+    "\n",
+    "        i_label = i_label + 1\n",
+    "        if(i_segments == N_k_band_segments - 1):\n",
+    "            label_flag[i_label] = label_flag_1\n",
+    "            i_label = i_label + 1\n",
+    "\n",
+    "    N_labels = i_label\n",
+    "    \n",
+    "    #------------Get the coordinates for the labels------------\n",
+    "    #label_coor_abs = np.zeros((N_labels)) #stores the absolute coordinates of the labels\n",
+    "    label_coor_relative = np.zeros((N_labels))\n",
+    "    for i_label in range(N_labels):\n",
+    "        #Here the evenly-distributed relative coordinates is used, because the coordinates of the labels could be too nerrow when using there absolute coordinates\n",
+    "        #x = labels_coor_0[0]\n",
+    "        #y = labels_coor_0[1]\n",
+    "        #z = labels_coor_0[2]\n",
+    "        #label_coor_abs[i_label] = np.sqrt(x*x+y*y+z*z)\n",
+    "        label_coor_relative[i_label] = step_k_point * N_k_points_per_segment * i_label / (1 + 1.0 / N_k_points_all);\n",
+    "\n",
+    "    #----Store the label-----------\n",
+    "    label_obj =[['' for i in range(2)] for j in range(N_labels)]\n",
+    "    for i_label in range(N_labels):\n",
+    "        label_obj[i_label][0] = label_coor_relative[i_label]\n",
+    "        label_obj[i_label][1] = label_flag[i_label]\n",
+    "        \n",
+    "    #print(label_obj)\n",
+    "        \n",
+    "  \n",
+    "    #Rescal the energies with respect to dos_fermi_energy\n",
+    "    for i_k_points in range(N_k_points_all):\n",
+    "        for i_bands in range(N_bands):\n",
+    "            band_energies_all[i_bands][i_k_points] =  band_energies_all[i_bands][i_k_points] - dos_fermi_energy\n",
+    "\n",
+    "    #-------Get VBM, CBM----------------\n",
+    "\n",
+    "    HOMO = -1000\n",
+    "    LUMO = 1000\n",
+    "    coor_k_point_HOMO = np.zeros((3)) #the coordinate of k point that stores HOMO\n",
+    "    coor_k_point_LUMO = np.zeros((3)) #the coordinate of k point that stores LUMO\n",
+    "    #band_gap_direct = 0.0\n",
+    "    band_gap_indirect = 0.0\n",
+    "    \n",
+    "    \n",
+    "    #band_energy_max = np.amax(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+    "    #band_energy_min = np.amin(band_energies[0])/ (1.60217656535* pow(10,-19))\n",
+    "    band_energy_max = 10\n",
+    "    band_energy_min = -10\n",
+    "    #N_band_energy_index = 10000\n",
+    "    #band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n",
+    "    #N_allowed_states = np.zeros(N_band_energy_index + 1)\n",
+    "    #i_index_fermi = math.floor((0 - band_energy_min) / band_energy_step) #the index that stores states at the Fermi level\n",
+    "\n",
+    "    for i_k_points_all in range(N_k_points_all):\n",
+    "        for i_bands in range(N_bands):\n",
+    "            #i_band_index = math.floor((band_energies_all[i_bands][i_k_points_all] - band_energy_min) / band_energy_step)\n",
+    "            #N_allowed_states[index_band_energy] = N_allowed_states[index_band_energy] + 1\n",
+    "            band_energy = band_energies_all[i_bands][i_k_points_all]\n",
+    "            if(band_energy > 0):\n",
+    "                if(band_energy < LUMO):\n",
+    "                    LUMO = band_energy\n",
+    "            else:\n",
+    "                if(band_energy > HOMO):\n",
+    "                    HOMO = band_energy\n",
+    "    #for i_band_index in range(i_index_fermi, N_band_energy_index): #get LUMO\n",
+    "    #    if(N_allowed_states[i_band_index] > 0):\n",
+    "    #        LUMO = band_energy_min + band_energy_step * i_band_index\n",
+    "    print('HOMO, LUMO: ',HOMO, LUMO)\n",
+    "    band_gap_indirect = abs(LUMO - HOMO)\n",
+    "    \n",
+    "    if(band_gap_indirect < 0.5): #VBM and CBM has to be found in another way for metals/charged system:\n",
+    "        HOMO = -1000\n",
+    "        LUMO = 1000\n",
+    "        band_energy_max = 10\n",
+    "        band_energy_min = 0\n",
+    "        N_band_energy_index = 10000\n",
+    "        band_energy_step = (band_energy_max - band_energy_min) / N_band_energy_index\n",
+    "        N_allowed_states = np.zeros(N_band_energy_index + 1)\n",
+    "        \n",
+    "        #get the DOS and store in N_allowed_states[]\n",
+    "        for i_k_points_all in range(N_k_points_all):\n",
+    "            for i_bands in range(N_bands):\n",
+    "                band_energy = band_energies_all[i_bands][i_k_points_all]\n",
+    "                if(band_energy_min < band_energy < band_energy_max):\n",
+    "                    i_band_index = math.floor((band_energy - band_energy_min) / band_energy_step)\n",
+    "                    N_allowed_states[i_band_index] = N_allowed_states[i_band_index] + 1\n",
+    "        if_gapped = 0\n",
+    "        for i_band_index in range(N_band_energy_index): #go through the energy levels from the bottom\n",
+    "            band_energy = band_energy_min + band_energy_step * i_band_index\n",
+    "            if(N_allowed_states[i_band_index] == 0):\n",
+    "                if_gapped = if_gapped + 1\n",
+    "            if(band_energy > band_energy_max - 0.5) and (if_gapped == 0):\n",
+    "                print(\"No gap found in this system. It seems to be a metal.\")\n",
+    "                HOMO = 1000\n",
+    "                LUMO = 1000\n",
+    "                break\n",
+    "            #print(\"At \", band_energy,\": # allowed states = \", N_allowed_states[i_band_index],\" if_gapped = \", if_gapped)\n",
+    "            \n",
+    "            if(N_allowed_states[i_band_index] > 0):\n",
+    "                if(if_gapped * band_energy_step> 0.3 ): #above VBM-CBM gap: LUMO\n",
+    "                    if(band_energy < LUMO):\n",
+    "                        #print(\"LUMO got!\")\n",
+    "                        LUMO = band_energy\n",
+    "                        break #break before touching another gap that is above the band gap\n",
+    "                if(if_gapped * band_energy_step < 0.3): #below VBM-CBM gap: HOMO\n",
+    "                    if(band_energy > HOMO):\n",
+    "                        #print(\"HOMO got!\")\n",
+    "                        HOMO = band_energy\n",
+    "                        \n",
+    "                if_gapped = 0\n",
+    "    \n",
+    "        print('HOMO, LUMO for metal/charged system: ',HOMO, LUMO)\n",
+    "    \n",
+    "    '''\n",
+    "\n",
+    "#    print('HOMO: ',tmp_HOMO_max)\n",
+    "    HOMO_global = tmp_HOMO_max\n",
+    "    LUMO_global = tmp_LUMO_min\n",
+    "    band_gap_indirect = LUMO_global - HOMO_global\n",
+    "    E_top_valence = HOMO_global\n",
+    "    if(band_gap_indirect < 0):\n",
+    "        band_gap_indirect = 0\n",
+    "\n",
+    "    #Rescal HOMO and LUMO with respect to HOMO\n",
+    "    HOMO_global = round((HOMO_global - E_top_valence), 3)\n",
+    "    LUMO_global = round((LUMO_global - E_top_valence), 3)\n",
+    "    '''\n",
+    "  \n",
+    "            \n",
+    "            \n",
+    "    #Find the position of HOMO, LUMO\n",
+    "\n",
+    "    for i_k_points in range(N_k_points_all):\n",
+    "        for i_bands in range(N_bands):\n",
+    "            if(abs(band_energies_all[i_bands][i_k_points] - HOMO) < 0.001):\n",
+    "                coor_k_point_HOMO = k_coor_1D[i_k_points]\n",
+    "            if(abs(band_energies_all[i_bands][i_k_points] - LUMO) < 0.001):\n",
+    "                coor_k_point_LUMO = k_coor_1D[i_k_points]  \n",
+    "\n",
+    "\n",
+    "               \n",
+    "                \n",
+    "    #Store the band data to band_obj\n",
+    "\n",
+    "    band_obj = {}\n",
+    "    band_obj[\"band_x_axis\"] = np.array(k_coor_1D).tolist()\n",
+    "    band_obj[\"band_y_axis\"] = np.array(band_energies_all).tolist()\n",
+    "    band_obj[\"labels\"] = np.array(label_obj).tolist()\n",
+    "    band_obj[\"HOMO_energy\"] = np.array(HOMO).tolist()\n",
+    "    band_obj[\"HOMO_coor\"] = np.array(coor_k_point_HOMO).tolist()\n",
+    "    band_obj[\"LUMO_energy\"] = np.array(LUMO).tolist()\n",
+    "    band_obj[\"LUMO_coor\"] = np.array(coor_k_point_LUMO).tolist()\n",
+    "    band_obj[\"average_N_k_points_per_inverse_distance\"] = np.array(average_N_k_points_per_inverse_distance).tolist()\n",
+    "    \n",
+    "\n",
+    "    \n",
+    "    return band_obj\n",
+    "\n",
+    "\n",
+    "#===============Get the space group information===========\n",
+    "def get_space_group(band_data):\n",
+    "    import pymatgen as mg\n",
+    "    from pymatgen.symmetry.analyzer import SpacegroupAnalyzer\n",
+    "\n",
+    "    simulation_cell = np.array(band_data[\"section_run\"][\"section_system\"][0].get('simulation_cell',\"empty\")) * 10000000000\n",
+    "    atom_positions = np.array(band_data[\"section_run\"][\"section_system\"][0].get('atom_positions',\"empty\")) * 10000000000\n",
+    "    atom_labels = np.array(band_data[\"section_run\"][\"section_system\"][0].get('atom_labels',\"empty\"))\n",
+    "    structure = mg.Structure(simulation_cell,atom_labels, atom_positions, coords_are_cartesian = True)\n",
+    "    \n",
+    "    finder = SpacegroupAnalyzer(structure, symprec=1e-3, angle_tolerance=5)\n",
+    "    space_group_symbol = finder.get_space_group_symbol()\n",
+    "    lattice_constant = []\n",
+    "    for item in structure.lattice.abc:\n",
+    "        lattice_constant.append(item)\n",
+    "    for i in range(len(lattice_constant)):\n",
+    "        item = str(round(lattice_constant[i], 3))\n",
+    "        lattice_constant[i] = item\n",
+    "    \n",
+    "    return [space_group_symbol, lattice_constant]\n",
+    "\n",
+    "#================Get the DOS data==============================\n",
+    "def get_dos_obj(dos_path):\n",
+    "    #dos_data: read from json file    \n",
+    "    #Load the data files for dos\n",
+    "    dos_data = load_jsonfile(dos_path)\n",
+    "\n",
+    "    print(dos_path)\n",
+    "    #N_dos_values = len(dos_data['sections']['section_run-0']['sections']['section_single_configuration_calculation-0']['section_dos'][0]['dos_energies'])\n",
+    "    N_dos_values = len(dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies'])\n",
+    "    #in new parser, it seems that the spin channel of 'dos_energies' disappears: Shape: [ number_of_dos_values ]\n",
+    "\n",
+    "    dos_energies = np.zeros((N_dos_values))\n",
+    "    dos_energies_tmp = np.zeros((N_dos_values)) #tmp array for unit convertion\n",
+    "    dos_values = np.zeros((N_dos_values))\n",
+    "\n",
+    "    dos_energies_tmp = dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_energies']\n",
+    "    dos_values =  dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0]['dos_values'][0]\n",
+    "    \n",
+    "\n",
+    "    dos_fermi_energy= dos_data['section_run']['section_single_configuration_calculation']['section_dos'][0].get('dos_fermi_energy',\"empty\")\n",
+    "    if(dos_fermi_energy == \"empty\"): #dos_fermi_energy is not available in EXCITING\n",
+    "        dos_fermi_energy_exciting = dos_data['section_run']['section_single_configuration_calculation'].get('x_exciting_dos_fermi',\"empty\")\n",
+    "        if(dos_fermi_energy_exciting == \"empty\"):\n",
+    "            dos_fermi_energy = 0\n",
+    "        else:\n",
+    "            dos_fermi_energy = dos_fermi_energy_exciting  / (1.60217656535 * pow(10,-19))\n",
+    "    else:\n",
+    "        dos_fermi_energy = dos_fermi_energy  / (1.60217656535 * pow(10,-19))\n",
+    "    print(\"dos_fermi_energy:\", dos_fermi_energy)\n",
+    "        \n",
+    "    for i_dos_values in range(N_dos_values):\n",
+    "        dos_energies[i_dos_values] = 0.0\n",
+    "        dos_energies[i_dos_values] = dos_energies_tmp[i_dos_values] / (1.60217656535 * pow(10,-19))\n",
+    "        dos_energies[i_dos_values] = round((dos_energies[i_dos_values] - dos_fermi_energy), 3) #reference with the fermi level\n",
+    "\n",
+    "    dos_obj = {}\n",
+    "    dos_obj[\"dos_x_axis\"] = np.array(dos_energies).tolist()\n",
+    "    dos_obj[\"dos_y_axis\"] = np.array(dos_values).tolist()\n",
+    "    dos_obj[\"dos_fermi_energy\"] = np.array(dos_fermi_energy).tolist()\n",
+    "\n",
+    "    return dos_obj\n",
+    "\n",
+    "\n",
+    "def get_info_obj(band_path):\n",
+    "\n",
+    "    #band_data: read from json file    \n",
+    "    #Load the data files for band\n",
+    "    band_data = load_jsonfile(band_path)\n",
+    "    info_obj = {}\n",
+    "    #---------Read the information of the calculation--------\n",
+    "    info_obj[\"program_name\"] = band_data[\"section_run\"][\"program_name\"];\n",
+    "    info_obj[\"program_basis_set_type\"] = band_data[\"section_run\"][\"program_basis_set_type\"];\n",
+    "    info_obj[\"atom_labels\"] = band_data[\"section_run\"][\"section_system\"][0][\"atom_labels\"];\n",
+    "    info_obj[\"XC_functional_name\"] = band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][0][\"XC_functional_name\"] + \" + \"+ band_data[\"section_run\"][\"section_method\"][\"section_XC_functionals\"][1][\"XC_functional_name\"];\n",
+    "    \n",
+    "    #----------Get the space group information----------\n",
+    "    \n",
+    "    [space_group_symbol, lattice_constant] = get_space_group(band_data)\n",
+    "    info_obj[\"space_group_symbol\"] = np.array(space_group_symbol).tolist()\n",
+    "    info_obj[\"lattice_constant\"] = np.array(lattice_constant).tolist()\n",
+    "    print(\"space group:\", info_obj[\"space_group_symbol\"])\n",
+    "    print(\"lattice_constant:\", lattice_constant)\n",
+    "    \n",
+    "    return info_obj\n",
+    "\n",
+    "\n",
+    "#============main===========================================\n",
+    "\n",
+    "#import matplotlib.pyplot as plt\n",
+    "band_obj_all = []\n",
+    "dos_obj_all = []\n",
+    "info_obj_all = []\n",
+    "print(\"Number of materials: \", N_materials)\n",
+    "\n",
+    "for i in range (N_materials):\n",
+    "    print(\"Material: \", i)\n",
+    "    band_path = band_paths[i]\n",
+    "    dos_path = dos_paths[i]\n",
+    "    \n",
+    "    \n",
+    "    dos_obj = get_dos_obj(dos_path)\n",
+    "    dos_fermi_energy = dos_obj[\"dos_fermi_energy\"]\n",
+    "    band_obj = get_band_obj(band_path, dos_fermi_energy)\n",
+    "    info_obj = get_info_obj(band_path)\n",
+    "    \n",
+    "    band_obj_all.append(band_obj)\n",
+    "    dos_obj_all.append(dos_obj)\n",
+    "    info_obj_all.append(info_obj)\n",
+    "    \n",
+    "    \n",
+    "    print(\"average_N_k_points_per_inverse_distance: \", band_obj[\"average_N_k_points_per_inverse_distance\"])\n",
+    "\n",
+    "print(\"Finish processing data.\")\n",
+    "\n",
+    "#run_cell_by_tag('save_data_to_js')\n",
+    "\n",
+    "print(\"Initialization of visulization finished.\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 331,
+   "metadata": {
+    "tags": [
+     "js_plot"
+    ]
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "  \n",
+       "var N_max_show = 10; //Number of results to be shown by default\n",
+       "\n",
+       "\n",
+       "\n",
+       "\n"
+      ],
+      "text/plain": [
+       "<IPython.core.display.Javascript object>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%javascript\n",
+    "  \n",
+    "var N_max_show = 10; //Number of results to be shown by default\n",
+    "\n",
+    "\n",
+    "\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%%javascript\n",
+    "// BACKUP!\n",
+    "/*\n",
+    "//Main plot function for given material:\n",
+    "    function plot_band_dos_i_backup(i, lowerLim, upperLim, if_show_VBM, if_compare, i_in_compare_list)\n",
+    "    {\n",
+    "        //alert(\"plot_band_dos_i\")\n",
+    "        //i=0;\n",
+    "        lowerLim = -10\n",
+    "        upperLim = 10\n",
+    "        if_show_VBM = 0\n",
+    "        if_compare = 0\n",
+    "        i_in_compare_list = -1\n",
+    "        //i=0;\n",
+    "        var placeholder_band = \"#div_band\" + i.toString();\n",
+    "        var placeholder_dos = \"#div_dos\" + i.toString();\n",
+    "        var placeholder_tools = \"#div_tools\" + i.toString();\n",
+    "        var placeholder_overview  = \"#div_overview\" + i.toString();\n",
+    "        var placeholder_overviewlegend = \"#overviewLegend\" + i.toString();\n",
+    "        var checkbox_VBM_id = \"checkbox_VBM\" + i.toString();\n",
+    "        var img_band_id = \"img_band\" + i.toString();\n",
+    "        var img_dos_id = \"img_dos\" + i.toString();\n",
+    "        var placeholder_band_compare = \"\";\n",
+    "\n",
+    "        if(i_in_compare_list == 1)\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_1\";\n",
+    "        }\n",
+    "        else if(i_in_compare_list == 2)\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_2\";\n",
+    "        }\n",
+    "        else\n",
+    "        {\n",
+    "            placeholder_band_compare = \"#div_band_compare_1\"; // just for safe\n",
+    "        }\n",
+    "\n",
+    "        Object.size = function(obj) {\n",
+    "            var size = 0, key;\n",
+    "            for (key in obj) \n",
+    "            {\n",
+    "                if (obj.hasOwnProperty(key)) size++;\n",
+    "            }\n",
+    "            return size;\n",
+    "        };\n",
+    "\n",
+    "        //Get the number of bands\n",
+    "        //alert(\"Getting band\")\n",
+    "        //alert(band_obj_all)\n",
+    "        //alert(\"band_obj_all got!\")\n",
+    "        var N_bands = Object.size(band_obj_all[i][\"band_y_axis\"]);\n",
+    "        var N_k_coors = Object.size(band_obj_all[i][\"band_x_axis\"]);\n",
+    "        alert(band_obj_all[i][\"band_y_axis\"])\n",
+    "        band_plotdata = [];\n",
+    "\n",
+    "        for(var i_band =0; i_band < N_bands; i_band++)\n",
+    "        {\n",
+    "          var tmp_data = [];\n",
+    "          for(var j_k_coor = 0; j_k_coor < N_k_coors; j_k_coor ++)\n",
+    "          {\n",
+    "            tmp_data.push([band_obj_all[i][\"band_x_axis\"][j_k_coor],band_obj_all[i][\"band_y_axis\"][i_band][j_k_coor]]);\n",
+    "          }\n",
+    "          plotData = { shadowSize: 0 , data: tmp_data, color: 'black',  series: { lines: { show: true } , points: {show: false} } };\n",
+    "          band_plotdata.push(plotData);\n",
+    "        }\n",
+    "\n",
+    "\n",
+    "        var tmp_data0 = [[0, 0], [1, 0]];\n",
+    "        plotData0 = { shadowSize:0, color: 'black', data: tmp_data0, dashes:{ show:true, lineWidth: 1.5}};\n",
+    "        band_plotdata.push(plotData0);\n",
+    "\n",
+    "        band_plotdata_overview = band_plotdata.slice(0);\n",
+    "\n",
+    "        var HOMOdata= [[band_obj_all[i][\"HOMO_coor\"],band_obj_all[i][\"HOMO_energy\"]]];\n",
+    "        HOMOlabel = [\"VBM\"];\n",
+    "        plotHOMO={ shadowSize:0, color: 'blue', data: HOMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'blue'},lines:{show: false},  showLabels: true, labels: HOMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+    "\n",
+    "        var LUMOdata= [[band_obj_all[i][\"LUMO_coor\"],band_obj_all[i][\"LUMO_energy\"]]];\n",
+    "        LUMOlabel = [\"CBM\"];\n",
+    "        plotLUMO={ shadowSize:0, color: 'red', data: LUMOdata, points:{show:true, radius: 4 , fill: true, fillColor: 'red'},lines:{show: false},  showLabels: true, labels: LUMOlabel, canvasRender: true, cColor: 'red', cFont:\"2em Arial\"};\n",
+    "\n",
+    "        //if_show_VBM = check_show_VBM(checkbox_VBM_id);\n",
+    "        if (if_show_VBM == 1)\n",
+    "        {\n",
+    "          band_plotdata.push(plotHOMO);\n",
+    "          band_plotdata.push(plotLUMO);\n",
+    "        }\n",
+    "\n",
+    " \n",
+    "        alert(img_band_id + band_plotdata)\n",
+    "            \n",
+    "        //!!!FIXME: if ($(\"#showVBM:checked\").length > 0 && gap > 0.1) \n",
+    "        //plotHOMOLUMO={ shadowSize:0, color: 'red', data: d5, points:{show:true, radius: 0.8 , fill: true}, showLabels: true, labels: d5label, labelPlacement: labelPos, canvasRender: true, cColor: 'red', cFont:\"1em Arial\"  }\n",
+    "\n",
+    "        var canvas_band;\n",
+    "        var options_band = {\n",
+    "          canvas: true,\n",
+    "          //legend:{ type: \"canvas\" },\n",
+    "          series: { lines: { show: true, lineWidth: 2 }, \n",
+    "          points: { show: false } }, \n",
+    "          xaxis: { \n",
+    "            ticks: band_obj_all[i][\"labels\"], \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20}, \n",
+    "            zoomRange: false,\n",
+    "            panRange: false \n",
+    "          }, \n",
+    "          yaxis: { \n",
+    "            axisLabel: \"Energy (eV)\", \n",
+    "            axisLabelUseCanvas: true,\n",
+    "            //axisLabelUseCanvas: false,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial', \n",
+    "            axisLabelPadding: 10, \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20, family:\"Arial\"},\n",
+    "            tickLength:-5, \n",
+    "            min: lowerLim, \n",
+    "            max: upperLim,\n",
+    "            tickDecimals: 0, \n",
+    "            zoomRange: [0.001, 1000],\n",
+    "            panRange: [-100, 100] \n",
+    "          },\n",
+    "\n",
+    "          zoom: { \n",
+    "            interactive: true\n",
+    "          },\n",
+    "\n",
+    "          pan: {\n",
+    "            interactive: true\n",
+    "          }, \n",
+    "\n",
+    "          //selection: { mode: \"xy\", color: \"#86a6b4\" }, \n",
+    "\n",
+    "          grid: { \n",
+    "            labelMargin: 15,\n",
+    "            hoverable: true, \n",
+    "            backgroundColor: { colors: [\"#fff\", \"#fff\"] }, \n",
+    "            borderWidth: {\n",
+    "              top: 2, \n",
+    "              right: 2,\n",
+    "              bottom: 2,\n",
+    "              left: 2,\n",
+    "              color : null } \n",
+    "          }\n",
+    "        }\n",
+    "        //var plot_band = $.plot($(placeholder_band), band_plotdata, options_band);\n",
+    "        //var plot_band = $.plot(\"#div_bandx\", band_plotdata, options_band);\n",
+    "        var plot_band = $.plot($(placeholder_band), band_plotdata, options_band).getCanvas(); // save the canvas\n",
+    "        image_band = plot_band.toDataURL();\n",
+    "        image_band = image_band.replace(\"image/png\",\"image/octet-stream\");\n",
+    "        //beakerx.image_band = image_band;\n",
+    "        document.getElementById(img_band_id).href= image_band;\n",
+    "        image_band_links[i] = image_band;\n",
+    "        alert(\"band plot done.\")\n",
+    "\n",
+    "\n",
+    "        //----Plot DOS----------------------\n",
+    "        var dos_plotdata = [];\n",
+    "        alert(\"dos:\"+dos_obj_all[i])\n",
+    "        var xdos = dos_obj_all[i][\"dos_x_axis\"];\n",
+    "        var ydos = dos_obj_all[i][\"dos_y_axis\"];\n",
+    "        var dosLabelPos = Math.max.apply(Math, ydos)/2;\n",
+    "        var d2 = [];\n",
+    "        for (var ii = 0; ii < xdos.length; ii+=1) {\n",
+    "          d2.push([ydos[ii],xdos[ii]]);\n",
+    "        }\n",
+    "        var plotData2={ shadowSize: 0, color: 'black' , data: d2}\n",
+    "        dos_plotdata.push(plotData2)\n",
+    "\n",
+    "        function find_xaxis_max_min(data, lowerbound, upperbound)\n",
+    "        {\n",
+    "                //data[xaxis,y] find the max and min value of x axis\n",
+    "                //alert(\"dos[0]:\" + data[0][\"data\"]);\n",
+    "                //alert(\"Bounds: \" + lowerbound + \" ,  \" + upperbound)\n",
+    "                var n_data = data.length;\n",
+    "                //alert(\"N dos: \" + n_data);\n",
+    "                var data_min = 1000000;\n",
+    "                var data_max = -1000000;\n",
+    "                var data_current = 0;\n",
+    "                for (var i = 0; i < n_data; i++)\n",
+    "                {\n",
+    "                    if((data[i][1] >= lowerbound) && (data[i][1] <= upperbound))\n",
+    "                    {\n",
+    "                        data_current = data[i][0];\n",
+    "                        //alert(\"data[i]: \" + data[i] + \"data[i][0]: \" + data_current);\n",
+    "                        if(data_current >= data_max)\n",
+    "                        {\n",
+    "                            data_max = data_current;\n",
+    "                        }\n",
+    "                        if(data_current <= data_min)\n",
+    "                        {\n",
+    "                            data_min = data_current;\n",
+    "                        }\n",
+    "                    }\n",
+    "                }\n",
+    "                var data_max_min = [data_max, data_min];\n",
+    "                //alert(\"data_max_min: \" + data_max_min);\n",
+    "                return data_max_min;\n",
+    "        }\n",
+    "        var dos_x_max_min = find_xaxis_max_min(dos_plotdata[0][\"data\"], lowerLim, upperLim);\n",
+    "        var dosLabelPos = (dos_x_max_min[0] + dos_x_max_min[1])/2;\n",
+    "\n",
+    "        var options_dos ={\n",
+    "          canvas: true,\n",
+    "          series: {\n",
+    "            lines: { show: true, lineWidth:2 },\n",
+    "            points: { show: false }\n",
+    "          },\n",
+    "\n",
+    "          yaxis: { \n",
+    "            axisLabel: \"\", \n",
+    "            axisLabelUseCanvas: true,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial', \n",
+    "            axisLabelPadding: 10, \n",
+    "            color:\"#000\", \n",
+    "            font: {size: 20},\n",
+    "            tickLength:-5, \n",
+    "            min: lowerLim, \n",
+    "            max: upperLim,\n",
+    "            tickDecimals: 0, \n",
+    "            zoomRange: [0.001, 1000],\n",
+    "            panRange: [-100, 100] \n",
+    "          },\n",
+    "\n",
+    "          xaxis: {\n",
+    "            axisLabel: \" \",\n",
+    "            axisLabelUseCanvas: false,\n",
+    "            axisLabelFontSizePixels: 20,\n",
+    "            axisLabelFontFamily: 'Arial',\n",
+    "            axisLabelPadding: 3,\n",
+    "            color:\"rgb(0, 0, 0)\",\n",
+    "            font: {size: 20, family:\"Arial\"},\n",
+    "            //ticks: 10,\n",
+    "            tickLength:0,\n",
+    "            min: dos_x_max_min[1],//0,\n",
+    "            max: dos_x_max_min[0],//1,\n",
+    "            tickDecimals: 0,\n",
+    "            ticks: [[ dosLabelPos ,'DOS']],\n",
+    "            //tickFormatter: MyFormatter\n",
+    "            panRange: false\n",
+    "          },\n",
+    "          pan: {\n",
+    "            interactive: true\n",
+    "          }, \n",
+    "\n",
+    "          grid: {\n",
+    "            labelMargin: 15,\n",
+    "            hoverable: true,\n",
+    "            //borderWidth : 1000,\n",
+    "            //show : false,\n",
+    "            //  //backgroundColor: { colors: [ \"#fff\", \"#eee\" ] },\n",
+    "            backgroundColor: { colors: [\"#fff\", \"#fff\"] },\n",
+    "            borderWidth: {\n",
+    "              top: 2,\n",
+    "              right: 2,\n",
+    "              bottom: 2,\n",
+    "              left: 2,\n",
+    "              color : null\n",
+    "            }\n",
+    "          }\n",
+    "        }\n",
+    "        var plot_dos = $.plot(placeholder_dos, dos_plotdata, options_dos).getCanvas();\n",
+    "        var image_dos = plot_dos.toDataURL();\n",
+    "        image_dos = image_dos.replace(\"image/png\",\"image/octet-stream\");\n",
+    "        image_dos = image_dos;\n",
+    "        document.getElementById(img_dos_id).href= image_dos;\n",
+    "        \n",
+    "    }\n",
+    "*/"
+   ]
+  }
+ ],
+ "metadata": {
+  "celltoolbar": "Tags",
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.6.7"
+  },
+  "toc": {
+   "base_numbering": 1,
+   "nav_menu": {},
+   "number_sections": false,
+   "sideBar": false,
+   "skip_h1_title": false,
+   "title_cell": "Table of Contents",
+   "title_sidebar": "Contents",
+   "toc_cell": false,
+   "toc_position": {},
+   "toc_section_display": false,
+   "toc_window_display": false
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/js/jquery-3.2.1.min.js b/js/jquery-3.2.1.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..644d35e274fd64ddaf6d12af813e820c424176a9
--- /dev/null
+++ b/js/jquery-3.2.1.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */
+!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=Array.isArray(d)))?(e?(e=!1,f=c&&Array.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e);return!1}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}return!1}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,N,e),g(f,c,O,e)):(f++,j.call(a,g(f,c,N,e),g(f,c,O,e),g(f,c,N,c.notifyWith))):(d!==N&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S),
+a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},U=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function V(){this.expando=r.expando+V.uid++}V.uid=1,V.prototype={cache:function(a){var b=a[this.expando];return b||(b={},U(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){Array.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(L)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var W=new V,X=new V,Y=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function $(a){return"true"===a||"false"!==a&&("null"===a?null:a===+a+""?+a:Y.test(a)?JSON.parse(a):a)}function _(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Z,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c=$(c)}catch(e){}X.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return X.hasData(a)||W.hasData(a)},data:function(a,b,c){return X.access(a,b,c)},removeData:function(a,b){X.remove(a,b)},_data:function(a,b,c){return W.access(a,b,c)},_removeData:function(a,b){W.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=X.get(f),1===f.nodeType&&!W.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),_(f,d,e[d])));W.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){X.set(this,a)}):T(this,function(b){var c;if(f&&void 0===b){if(c=X.get(f,a),void 0!==c)return c;if(c=_(f,a),void 0!==c)return c}else this.each(function(){X.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=W.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var aa=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ba=new RegExp("^(?:([+-])=|)("+aa+")([a-z%]*)$","i"),ca=["Top","Right","Bottom","Left"],da=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ea=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function fa(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&ba.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ga={};function ha(a){var b,c=a.ownerDocument,d=a.nodeName,e=ga[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ga[d]=e,e)}function ia(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=W.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&da(d)&&(e[f]=ha(d))):"none"!==c&&(e[f]="none",W.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ia(this,!0)},hide:function(){return ia(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){da(this)?r(this).show():r(this).hide()})}});var ja=/^(?:checkbox|radio)$/i,ka=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c<d;c++)W.set(a[c],"globalEval",!b||W.get(b[c],"globalEval"))}var pa=/<|&#?\w+;/;function qa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(pa.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ka.exec(f)||["",""])[1].toLowerCase(),i=ma[h]||ma._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g,h=[],i=b.delegateCount,j=a.target;if(i&&j.nodeType&&!("click"===a.type&&a.button>=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c<i;c++)d=b[c],e=d.selector+" ",void 0===g[e]&&(g[e]=d.needsContext?r(e,this).index(j)>-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i<b.length&&h.push({elem:j,handlers:b.slice(i)}),h},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==xa()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===xa()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&B(this,"input"))return this.click(),!1},_default:function(a){return B(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?va:wa,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:wa,isPropagationStopped:wa,isImmediatePropagationStopped:wa,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=va,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=va,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=va,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&sa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ta.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return ya(this,a,b,c,d)},one:function(a,b,c,d){return ya(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=wa),this.each(function(){r.event.remove(this,a,c,b)})}});var za=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/<script|<style|<link/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,Ca=/^true\/(.*)/,Da=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}X.hasData(a)&&(h=X.access(a),i=r.extend({},h),X.set(b,i))}}function Ia(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ja.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ja(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,na(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ga),l=0;l<i;l++)j=h[l],la.test(j.type||"")&&!W.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Da,""),k))}return a}function Ka(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(na(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&oa(na(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(za,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d<e;d++)Ia(f[d],g[d]);if(b)if(c)for(f=f||na(a),g=g||na(h),d=0,e=f.length;d<e;d++)Ha(f[d],g[d]);else Ha(a,h);return g=na(h,"script"),g.length>0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(na(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ja(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(na(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var La=/^margin/,Ma=new RegExp("^("+aa+")(?!px)[a-z%]+$","i"),Na=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",ra.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,ra.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Oa(a,b,c){var d,e,f,g,h=a.style;return c=c||Na(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ma.test(g)&&La.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Pa(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Qa=/^(none|table(?!-c[ea]).+)/,Ra=/^--/,Sa={position:"absolute",visibility:"hidden",display:"block"},Ta={letterSpacing:"0",fontWeight:"400"},Ua=["Webkit","Moz","ms"],Va=d.createElement("div").style;function Wa(a){if(a in Va)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ua.length;while(c--)if(a=Ua[c]+b,a in Va)return a}function Xa(a){var b=r.cssProps[a];return b||(b=r.cssProps[a]=Wa(a)||a),b}function Ya(a,b,c){var d=ba.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Za(a,b,c,d,e){var f,g=0;for(f=c===(d?"border":"content")?4:"width"===b?1:0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+ca[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+ca[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+ca[f]+"Width",!0,e))):(g+=r.css(a,"padding"+ca[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+ca[f]+"Width",!0,e)));return g}function $a(a,b,c){var d,e=Na(a),f=Oa(a,b,e),g="border-box"===r.css(a,"boxSizing",!1,e);return Ma.test(f)?f:(d=g&&(o.boxSizingReliable()||f===a.style[b]),"auto"===f&&(f=a["offset"+b[0].toUpperCase()+b.slice(1)]),f=parseFloat(f)||0,f+Za(a,b,c||(g?"border":"content"),d,e)+"px")}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Oa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=Ra.test(b),j=a.style;return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:j[b]:(f=typeof c,"string"===f&&(e=ba.exec(c))&&e[1]&&(c=fa(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(j[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i?j.setProperty(b,c):j[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b),i=Ra.test(b);return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Oa(a,b,d)),"normal"===e&&b in Ta&&(e=Ta[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Qa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?$a(a,b,d):ea(a,Sa,function(){return $a(a,b,d)})},set:function(a,c,d){var e,f=d&&Na(a),g=d&&Za(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=ba.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ya(a,c,g)}}}),r.cssHooks.marginLeft=Pa(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Oa(a,"marginLeft"))||a.getBoundingClientRect().left-ea(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+ca[d]+b]=f[d]||f[d-2]||f[0];return e}},La.test(a)||(r.cssHooks[a+b].set=Ya)}),r.fn.extend({css:function(a,b){return T(this,function(a,b,c){var d,e,f={},g=0;if(Array.isArray(b)){for(d=Na(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&da(a),q=W.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],cb.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=W.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ia([a],!0),j=a.style.display||j,k=r.css(a,"display"),ia([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=W.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ia([a],!0),m.done(function(){p||ia([a]),W.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=hb(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],Array.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=kb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=ab||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(i||h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:ab||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);f<g;f++)if(d=kb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,hb,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j}r.Animation=r.extend(kb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return fa(c.elem,a,ba.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(L);for(var c,d=0,e=a.length;d<e;d++)c=a[d],kb.tweeners[c]=kb.tweeners[c]||[],kb.tweeners[c].unshift(b)},prefilters:[ib],prefilter:function(a,b){b?kb.prefilters.unshift(a):kb.prefilters.push(a)}}),r.speed=function(a,b,c){var d=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off?d.duration=0:"number"!=typeof d.duration&&(d.duration in r.fx.speeds?d.duration=r.fx.speeds[d.duration]:d.duration=r.fx.speeds._default),null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){r.isFunction(d.old)&&d.old.call(this),d.queue&&r.dequeue(this,d.queue)},d},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(da).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=kb(this,r.extend({},a),f);(e||W.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=W.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&db.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=W.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),r.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(ab=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),ab=void 0},r.fx.timer=function(a){r.timers.push(a),r.fx.start()},r.fx.interval=13,r.fx.start=function(){bb||(bb=!0,eb())},r.fx.stop=function(){bb=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var lb,mb=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return T(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),
+null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d<i;d++)if(c=e[d],(c.selected||d===f)&&!c.disabled&&(!c.parentNode.disabled||!B(c.parentNode,"optgroup"))){if(b=r(c).val(),g)return b;h.push(b)}return h},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Tb=[],Ub=/(=)\?(?=&|$)|\?\?/;r.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Tb.pop()||r.expando+"_"+ub++;return this[a]=!0,a}}),r.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Ub.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ub.test(b.data)&&"data");if(h||"jsonp"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Ub,"$1"+e):b.jsonp!==!1&&(b.url+=(vb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||r.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Tb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),"script"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=C.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=qa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=pb(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&r.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?r("<div>").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length},r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),b=f.ownerDocument,c=b.documentElement,e=b.defaultView,{top:d.top+e.pageYOffset-c.clientTop,left:d.left+e.pageXOffset-c.clientLeft}):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),B(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||ra})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return T(this,function(a,d,e){var f;return r.isWindow(a)?f=a:9===a.nodeType&&(f=a.defaultView),void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Pa(o.pixelPosition,function(a,c){if(c)return c=Oa(a,b),Ma.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return T(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.holdReady=function(a){a?r.readyWait++:r.ready(!0)},r.isArray=Array.isArray,r.parseJSON=JSON.parse,r.nodeName=B,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var Vb=a.jQuery,Wb=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Wb),b&&a.jQuery===r&&(a.jQuery=Vb),r},b||(a.jQuery=a.$=r),r});
diff --git a/js/jquery.event.move.js b/js/jquery.event.move.js
new file mode 100644
index 0000000000000000000000000000000000000000..a792b71330e21da38fdb543f6f754cd61dd9103b
--- /dev/null
+++ b/js/jquery.event.move.js
@@ -0,0 +1,599 @@
+// DOM.event.move
+//
+// 2.0.0
+//
+// Stephen Band
+//
+// Triggers 'movestart', 'move' and 'moveend' events after
+// mousemoves following a mousedown cross a distance threshold,
+// similar to the native 'dragstart', 'drag' and 'dragend' events.
+// Move events are throttled to animation frames. Move event objects
+// have the properties:
+//
+// pageX:
+// pageY:     Page coordinates of pointer.
+// startX:
+// startY:    Page coordinates of pointer at movestart.
+// distX:
+// distY:     Distance the pointer has moved since movestart.
+// deltaX:
+// deltaY:    Distance the finger has moved since last event.
+// velocityX:
+// velocityY: Average velocity over last few events.
+
+
+(function(fn) {
+	if (typeof define === 'function' && define.amd) {
+        define([], fn);
+    } else if ((typeof module !== "undefined" && module !== null) && module.exports) {
+        module.exports = fn;
+	} else {
+		fn();
+	}
+})(function(){
+	var assign = Object.assign || window.jQuery && jQuery.extend;
+
+	// Number of pixels a pressed pointer travels before movestart
+	// event is fired.
+	var threshold = 8;
+
+	// Shim for requestAnimationFrame, falling back to timer. See:
+	// see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+	var requestFrame = (function(){
+		return (
+			window.requestAnimationFrame ||
+			window.webkitRequestAnimationFrame ||
+			window.mozRequestAnimationFrame ||
+			window.oRequestAnimationFrame ||
+			window.msRequestAnimationFrame ||
+			function(fn, element){
+				return window.setTimeout(function(){
+					fn();
+				}, 25);
+			}
+		);
+	})();
+	
+	// Shim for customEvent
+	// see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
+	(function () {
+		if ( typeof window.CustomEvent === "function" ) return false;
+		function CustomEvent ( event, params ) {
+			params = params || { bubbles: false, cancelable: false, detail: undefined };
+			var evt = document.createEvent( 'CustomEvent' );
+			evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
+			return evt;
+		}
+		
+		CustomEvent.prototype = window.Event.prototype;
+		window.CustomEvent = CustomEvent;
+	})();
+
+	var ignoreTags = {
+			textarea: true,
+			input: true,
+			select: true,
+			button: true
+		};
+
+	var mouseevents = {
+		move:   'mousemove',
+		cancel: 'mouseup dragstart',
+		end:    'mouseup'
+	};
+
+	var touchevents = {
+		move:   'touchmove',
+		cancel: 'touchend',
+		end:    'touchend'
+	};
+
+	var rspaces = /\s+/;
+
+
+	// DOM Events
+
+	var eventOptions = { bubbles: true, cancelable: true };
+
+	var eventsSymbol = typeof Symbol === "function" ? Symbol('events') : {};
+
+	function createEvent(type) {
+		return new CustomEvent(type, eventOptions);
+	}
+
+	function getEvents(node) {
+		return node[eventsSymbol] || (node[eventsSymbol] = {});
+	}
+
+	function on(node, types, fn, data, selector) {
+		types = types.split(rspaces);
+
+		var events = getEvents(node);
+		var i = types.length;
+		var handlers, type;
+
+		function handler(e) { fn(e, data); }
+
+		while (i--) {
+			type = types[i];
+			handlers = events[type] || (events[type] = []);
+			handlers.push([fn, handler]);
+			node.addEventListener(type, handler);
+		}
+	}
+
+	function off(node, types, fn, selector) {
+		types = types.split(rspaces);
+
+		var events = getEvents(node);
+		var i = types.length;
+		var type, handlers, k;
+
+		if (!events) { return; }
+
+		while (i--) {
+			type = types[i];
+			handlers = events[type];
+			if (!handlers) { continue; }
+			k = handlers.length;
+			while (k--) {
+				if (handlers[k][0] === fn) {
+					node.removeEventListener(type, handlers[k][1]);
+					handlers.splice(k, 1);
+				}
+			}
+		}
+	}
+
+	function trigger(node, type, properties) {
+		// Don't cache events. It prevents you from triggering an event of a
+		// given type from inside the handler of another event of that type.
+		var event = createEvent(type);
+		if (properties) { assign(event, properties); }
+		node.dispatchEvent(event);
+	}
+
+
+	// Constructors
+
+	function Timer(fn){
+		var callback = fn,
+		    active = false,
+		    running = false;
+
+		function trigger(time) {
+			if (active){
+				callback();
+				requestFrame(trigger);
+				running = true;
+				active = false;
+			}
+			else {
+				running = false;
+			}
+		}
+
+		this.kick = function(fn) {
+			active = true;
+			if (!running) { trigger(); }
+		};
+
+		this.end = function(fn) {
+			var cb = callback;
+
+			if (!fn) { return; }
+
+			// If the timer is not running, simply call the end callback.
+			if (!running) {
+				fn();
+			}
+			// If the timer is running, and has been kicked lately, then
+			// queue up the current callback and the end callback, otherwise
+			// just the end callback.
+			else {
+				callback = active ?
+					function(){ cb(); fn(); } :
+					fn ;
+
+				active = true;
+			}
+		};
+	}
+
+
+	// Functions
+
+	function noop() {}
+
+	function preventDefault(e) {
+		e.preventDefault();
+	}
+
+	function isIgnoreTag(e) {
+		return !!ignoreTags[e.target.tagName.toLowerCase()];
+	}
+
+	function isPrimaryButton(e) {
+		// Ignore mousedowns on any button other than the left (or primary)
+		// mouse button, or when a modifier key is pressed.
+		return (e.which === 1 && !e.ctrlKey && !e.altKey);
+	}
+
+	function identifiedTouch(touchList, id) {
+		var i, l;
+
+		if (touchList.identifiedTouch) {
+			return touchList.identifiedTouch(id);
+		}
+
+		// touchList.identifiedTouch() does not exist in
+		// webkit yet… we must do the search ourselves...
+
+		i = -1;
+		l = touchList.length;
+
+		while (++i < l) {
+			if (touchList[i].identifier === id) {
+				return touchList[i];
+			}
+		}
+	}
+
+	function changedTouch(e, data) {
+		var touch = identifiedTouch(e.changedTouches, data.identifier);
+
+		// This isn't the touch you're looking for.
+		if (!touch) { return; }
+
+		// Chrome Android (at least) includes touches that have not
+		// changed in e.changedTouches. That's a bit annoying. Check
+		// that this touch has changed.
+		if (touch.pageX === data.pageX && touch.pageY === data.pageY) { return; }
+
+		return touch;
+	}
+
+
+	// Handlers that decide when the first movestart is triggered
+
+	function mousedown(e){
+		// Ignore non-primary buttons
+		if (!isPrimaryButton(e)) { return; }
+
+		// Ignore form and interactive elements
+		if (isIgnoreTag(e)) { return; }
+
+		on(document, mouseevents.move, mousemove, e);
+		on(document, mouseevents.cancel, mouseend, e);
+	}
+
+	function mousemove(e, data){
+		checkThreshold(e, data, e, removeMouse);
+	}
+
+	function mouseend(e, data) {
+		removeMouse();
+	}
+
+	function removeMouse() {
+		off(document, mouseevents.move, mousemove);
+		off(document, mouseevents.cancel, mouseend);
+	}
+
+	function touchstart(e) {
+		// Don't get in the way of interaction with form elements
+		if (ignoreTags[e.target.tagName.toLowerCase()]) { return; }
+
+		var touch = e.changedTouches[0];
+
+		// iOS live updates the touch objects whereas Android gives us copies.
+		// That means we can't trust the touchstart object to stay the same,
+		// so we must copy the data. This object acts as a template for
+		// movestart, move and moveend event objects.
+		var data = {
+			target:     touch.target,
+			pageX:      touch.pageX,
+			pageY:      touch.pageY,
+			identifier: touch.identifier,
+
+			// The only way to make handlers individually unbindable is by
+			// making them unique.
+			touchmove:  function(e, data) { touchmove(e, data); },
+			touchend:   function(e, data) { touchend(e, data); }
+		};
+
+		on(document, touchevents.move, data.touchmove, data);
+		on(document, touchevents.cancel, data.touchend, data);
+	}
+
+	function touchmove(e, data) {
+		var touch = changedTouch(e, data);
+		if (!touch) { return; }
+		checkThreshold(e, data, touch, removeTouch);
+	}
+
+	function touchend(e, data) {
+		var touch = identifiedTouch(e.changedTouches, data.identifier);
+		if (!touch) { return; }
+		removeTouch(data);
+	}
+
+	function removeTouch(data) {
+		off(document, touchevents.move, data.touchmove);
+		off(document, touchevents.cancel, data.touchend);
+	}
+
+	function checkThreshold(e, data, touch, fn) {
+		var distX = touch.pageX - data.pageX;
+		var distY = touch.pageY - data.pageY;
+
+		// Do nothing if the threshold has not been crossed.
+		if ((distX * distX) + (distY * distY) < (threshold * threshold)) { return; }
+
+		triggerStart(e, data, touch, distX, distY, fn);
+	}
+
+	function triggerStart(e, data, touch, distX, distY, fn) {
+		var touches = e.targetTouches;
+		var time = e.timeStamp - data.timeStamp;
+
+		// Create a movestart object with some special properties that
+		// are passed only to the movestart handlers.
+		var template = {
+			altKey:     e.altKey,
+			ctrlKey:    e.ctrlKey,
+			shiftKey:   e.shiftKey,
+			startX:     data.pageX,
+			startY:     data.pageY,
+			distX:      distX,
+			distY:      distY,
+			deltaX:     distX,
+			deltaY:     distY,
+			pageX:      touch.pageX,
+			pageY:      touch.pageY,
+			velocityX:  distX / time,
+			velocityY:  distY / time,
+			identifier: data.identifier,
+			targetTouches: touches,
+			finger: touches ? touches.length : 1,
+			enableMove: function() {
+				this.moveEnabled = true;
+				this.enableMove = noop;
+				e.preventDefault();
+			}
+		};
+
+		// Trigger the movestart event.
+		trigger(data.target, 'movestart', template);
+
+		// Unbind handlers that tracked the touch or mouse up till now.
+		fn(data);
+	}
+
+
+	// Handlers that control what happens following a movestart
+
+	function activeMousemove(e, data) {
+		var timer  = data.timer;
+
+		data.touch = e;
+		data.timeStamp = e.timeStamp;
+		timer.kick();
+	}
+
+	function activeMouseend(e, data) {
+		var target = data.target;
+		var event  = data.event;
+		var timer  = data.timer;
+
+		removeActiveMouse();
+
+		endEvent(target, event, timer, function() {
+			// Unbind the click suppressor, waiting until after mouseup
+			// has been handled.
+			setTimeout(function(){
+				off(target, 'click', preventDefault);
+			}, 0);
+		});
+	}
+
+	function removeActiveMouse() {
+		off(document, mouseevents.move, activeMousemove);
+		off(document, mouseevents.end, activeMouseend);
+	}
+
+	function activeTouchmove(e, data) {
+		var event = data.event;
+		var timer = data.timer;
+		var touch = changedTouch(e, event);
+
+		if (!touch) { return; }
+
+		// Stop the interface from gesturing
+		e.preventDefault();
+
+		event.targetTouches = e.targetTouches;
+		data.touch = touch;
+		data.timeStamp = e.timeStamp;
+
+		timer.kick();
+	}
+
+	function activeTouchend(e, data) {
+		var target = data.target;
+		var event  = data.event;
+		var timer  = data.timer;
+		var touch  = identifiedTouch(e.changedTouches, event.identifier);
+
+		// This isn't the touch you're looking for.
+		if (!touch) { return; }
+
+		removeActiveTouch(data);
+		endEvent(target, event, timer);
+	}
+
+	function removeActiveTouch(data) {
+		off(document, touchevents.move, data.activeTouchmove);
+		off(document, touchevents.end, data.activeTouchend);
+	}
+
+
+	// Logic for triggering move and moveend events
+
+	function updateEvent(event, touch, timeStamp) {
+		var time = timeStamp - event.timeStamp;
+
+		event.distX =  touch.pageX - event.startX;
+		event.distY =  touch.pageY - event.startY;
+		event.deltaX = touch.pageX - event.pageX;
+		event.deltaY = touch.pageY - event.pageY;
+
+		// Average the velocity of the last few events using a decay
+		// curve to even out spurious jumps in values.
+		event.velocityX = 0.3 * event.velocityX + 0.7 * event.deltaX / time;
+		event.velocityY = 0.3 * event.velocityY + 0.7 * event.deltaY / time;
+		event.pageX =  touch.pageX;
+		event.pageY =  touch.pageY;
+	}
+
+	function endEvent(target, event, timer, fn) {
+		timer.end(function(){
+			trigger(target, 'moveend', event);
+			return fn && fn();
+		});
+	}
+
+
+	// Set up the DOM
+
+	function movestart(e) {
+		if (e.defaultPrevented) { return; }
+		if (!e.moveEnabled) { return; }
+
+		var event = {
+			startX:        e.startX,
+			startY:        e.startY,
+			pageX:         e.pageX,
+			pageY:         e.pageY,
+			distX:         e.distX,
+			distY:         e.distY,
+			deltaX:        e.deltaX,
+			deltaY:        e.deltaY,
+			velocityX:     e.velocityX,
+			velocityY:     e.velocityY,
+			identifier:    e.identifier,
+			targetTouches: e.targetTouches,
+			finger:        e.finger
+		};
+
+		var data = {
+			target:    e.target,
+			event:     event,
+			timer:     new Timer(update),
+			touch:     undefined,
+			timeStamp: e.timeStamp
+		};
+
+		function update(time) {
+			updateEvent(event, data.touch, data.timeStamp);
+			trigger(data.target, 'move', event);
+		}
+
+		if (e.identifier === undefined) {
+			// We're dealing with a mouse event.
+			// Stop clicks from propagating during a move
+			on(e.target, 'click', preventDefault);
+			on(document, mouseevents.move, activeMousemove, data);
+			on(document, mouseevents.end, activeMouseend, data);
+		}
+		else {
+			// In order to unbind correct handlers they have to be unique
+			data.activeTouchmove = function(e, data) { activeTouchmove(e, data); };
+			data.activeTouchend = function(e, data) { activeTouchend(e, data); };
+
+			// We're dealing with a touch.
+			on(document, touchevents.move, data.activeTouchmove, data);
+			on(document, touchevents.end, data.activeTouchend, data);
+		}
+	}
+
+	on(document, 'mousedown', mousedown);
+	on(document, 'touchstart', touchstart);
+	on(document, 'movestart', movestart);
+
+
+	// jQuery special events
+	//
+	// jQuery event objects are copies of DOM event objects. They need
+	// a little help copying the move properties across.
+
+	if (!window.jQuery) { return; }
+
+	var properties = ("startX startY pageX pageY distX distY deltaX deltaY velocityX velocityY").split(' ');
+
+	function enableMove1(e) { e.enableMove(); }
+	function enableMove2(e) { e.enableMove(); }
+	function enableMove3(e) { e.enableMove(); }
+
+	function add(handleObj) {
+		var handler = handleObj.handler;
+
+		handleObj.handler = function(e) {
+			// Copy move properties across from originalEvent
+			var i = properties.length;
+			var property;
+
+			while(i--) {
+				property = properties[i];
+				e[property] = e.originalEvent[property];
+			}
+
+			handler.apply(this, arguments);
+		};
+	}
+
+	jQuery.event.special.movestart = {
+		setup: function() {
+			// Movestart must be enabled to allow other move events
+			on(this, 'movestart', enableMove1);
+
+			// Do listen to DOM events
+			return false;
+		},
+
+		teardown: function() {
+			off(this, 'movestart', enableMove1);
+			return false;
+		},
+
+		add: add
+	};
+
+	jQuery.event.special.move = {
+		setup: function() {
+			on(this, 'movestart', enableMove2);
+			return false;
+		},
+
+		teardown: function() {
+			off(this, 'movestart', enableMove2);
+			return false;
+		},
+
+		add: add
+	};
+
+	jQuery.event.special.moveend = {
+		setup: function() {
+			on(this, 'movestart', enableMove3);
+			return false;
+		},
+
+		teardown: function() {
+			off(this, 'movestart', enableMove3);
+			return false;
+		},
+
+		add: add
+	};
+});
diff --git a/js/jquery.flot.axislabels.js b/js/jquery.flot.axislabels.js
new file mode 100644
index 0000000000000000000000000000000000000000..cda8038953c76b039e3ab0f1c49607dcbcf6c3ce
--- /dev/null
+++ b/js/jquery.flot.axislabels.js
@@ -0,0 +1,462 @@
+/*
+Axis Labels Plugin for flot.
+http://github.com/markrcote/flot-axislabels
+Original code is Copyright (c) 2010 Xuan Luo.
+Original code was released under the GPLv3 license by Xuan Luo, September 2010.
+Original code was rereleased under the MIT license by Xuan Luo, April 2012.
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+(function ($) {
+    var options = {
+      axisLabels: {
+        show: true
+      }
+    };
+
+    function canvasSupported() {
+        return !!document.createElement('canvas').getContext;
+    }
+
+    function canvasTextSupported() {
+        if (!canvasSupported()) {
+            return false;
+        }
+        var dummy_canvas = document.createElement('canvas');
+        var context = dummy_canvas.getContext('2d');
+        return typeof context.fillText == 'function';
+    }
+
+    function css3TransitionSupported() {
+        var div = document.createElement('div');
+        return typeof div.style.MozTransition != 'undefined'    // Gecko
+            || typeof div.style.OTransition != 'undefined'      // Opera
+            || typeof div.style.webkitTransition != 'undefined' // WebKit
+            || typeof div.style.transition != 'undefined';
+    }
+
+
+    function AxisLabel(axisName, position, padding, plot, opts) {
+        this.axisName = axisName;
+        this.position = position;
+        this.padding = padding;
+        this.plot = plot;
+        this.opts = opts;
+        this.width = 0;
+        this.height = 0;
+    }
+
+    AxisLabel.prototype.cleanup = function() {
+    };
+
+
+    CanvasAxisLabel.prototype = new AxisLabel();
+    CanvasAxisLabel.prototype.constructor = CanvasAxisLabel;
+    function CanvasAxisLabel(axisName, position, padding, plot, opts) {
+        AxisLabel.prototype.constructor.call(this, axisName, position, padding,
+                                             plot, opts);
+    }
+
+    CanvasAxisLabel.prototype.calculateSize = function() {
+        if (!this.opts.axisLabelFontSizePixels)
+            this.opts.axisLabelFontSizePixels = 14;
+        if (!this.opts.axisLabelFontFamily)
+            this.opts.axisLabelFontFamily = 'sans-serif';
+
+        var textWidth = this.opts.axisLabelFontSizePixels + this.padding;
+        var textHeight = this.opts.axisLabelFontSizePixels + this.padding;
+        if (this.position == 'left' || this.position == 'right') {
+            this.width = this.opts.axisLabelFontSizePixels + this.padding;
+            this.height = 0;
+        } else {
+            this.width = 0;
+            this.height = this.opts.axisLabelFontSizePixels + this.padding;
+        }
+    };
+
+    CanvasAxisLabel.prototype.draw = function(box) {
+        if (!this.opts.axisLabelColour)
+            this.opts.axisLabelColour = 'black';
+        var ctx = this.plot.getCanvas().getContext('2d');
+        ctx.save();
+        ctx.font = this.opts.axisLabelFontSizePixels + 'px ' +
+            this.opts.axisLabelFontFamily;
+        ctx.fillStyle = this.opts.axisLabelColour;
+        var width = ctx.measureText(this.opts.axisLabel).width;
+        var height = this.opts.axisLabelFontSizePixels;
+        var x, y, angle = 0;
+        if (this.position == 'top') {
+            x = box.left + box.width/2 - width/2;
+            y = box.top + height*0.72;
+        } else if (this.position == 'bottom') {
+            x = box.left + box.width/2 - width/2;
+            y = box.top + box.height - height*0.72;
+        } else if (this.position == 'left') {
+            x = box.left + height*0.72;
+            y = box.height/2 + box.top + width/2;
+            angle = -Math.PI/2;
+        } else if (this.position == 'right') {
+            x = box.left + box.width - height*0.72;
+            y = box.height/2 + box.top - width/2;
+            angle = Math.PI/2;
+        }
+        ctx.translate(x, y);
+        ctx.rotate(angle);
+        ctx.fillText(this.opts.axisLabel, 0, 0);
+        ctx.restore();
+    };
+
+
+    HtmlAxisLabel.prototype = new AxisLabel();
+    HtmlAxisLabel.prototype.constructor = HtmlAxisLabel;
+    function HtmlAxisLabel(axisName, position, padding, plot, opts) {
+        AxisLabel.prototype.constructor.call(this, axisName, position,
+                                             padding, plot, opts);
+        this.elem = null;
+    }
+
+    HtmlAxisLabel.prototype.calculateSize = function() {
+        var elem = $('<div class="axisLabels" style="position:absolute;">' +
+                     this.opts.axisLabel + '</div>');
+        this.plot.getPlaceholder().append(elem);
+        // store height and width of label itself, for use in draw()
+        this.labelWidth = elem.outerWidth(true);
+        this.labelHeight = elem.outerHeight(true);
+        elem.remove();
+
+        this.width = this.height = 0;
+        if (this.position == 'left' || this.position == 'right') {
+            this.width = this.labelWidth + this.padding;
+        } else {
+            this.height = this.labelHeight + this.padding;
+        }
+    };
+
+    HtmlAxisLabel.prototype.cleanup = function() {
+        if (this.elem) {
+            this.elem.remove();
+        }
+    };
+
+    HtmlAxisLabel.prototype.draw = function(box) {
+        this.plot.getPlaceholder().find('#' + this.axisName + 'Label').remove();
+        this.elem = $('<div id="' + this.axisName +
+                      'Label" " class="axisLabels" style="position:absolute;">'
+                      + this.opts.axisLabel + '</div>');
+        this.plot.getPlaceholder().append(this.elem);
+        if (this.position == 'top') {
+            this.elem.css('left', box.left + box.width/2 - this.labelWidth/2 +
+                          'px');
+            this.elem.css('top', box.top + 'px');
+        } else if (this.position == 'bottom') {
+            this.elem.css('left', box.left + box.width/2 - this.labelWidth/2 +
+                          'px');
+            this.elem.css('top', box.top + box.height - this.labelHeight +
+                          'px');
+        } else if (this.position == 'left') {
+            this.elem.css('top', box.top + box.height/2 - this.labelHeight/2 +
+                          'px');
+            this.elem.css('left', box.left + 'px');
+        } else if (this.position == 'right') {
+            this.elem.css('top', box.top + box.height/2 - this.labelHeight/2 +
+                          'px');
+            this.elem.css('left', box.left + box.width - this.labelWidth +
+                          'px');
+        }
+    };
+
+
+    CssTransformAxisLabel.prototype = new HtmlAxisLabel();
+    CssTransformAxisLabel.prototype.constructor = CssTransformAxisLabel;
+    function CssTransformAxisLabel(axisName, position, padding, plot, opts) {
+        HtmlAxisLabel.prototype.constructor.call(this, axisName, position,
+                                                 padding, plot, opts);
+    }
+
+    CssTransformAxisLabel.prototype.calculateSize = function() {
+        HtmlAxisLabel.prototype.calculateSize.call(this);
+        this.width = this.height = 0;
+        if (this.position == 'left' || this.position == 'right') {
+            this.width = this.labelHeight + this.padding;
+        } else {
+            this.height = this.labelHeight + this.padding;
+        }
+    };
+
+    CssTransformAxisLabel.prototype.transforms = function(degrees, x, y) {
+        var stransforms = {
+            '-moz-transform': '',
+            '-webkit-transform': '',
+            '-o-transform': '',
+            '-ms-transform': ''
+        };
+        if (x != 0 || y != 0) {
+            var stdTranslate = ' translate(' + x + 'px, ' + y + 'px)';
+            stransforms['-moz-transform'] += stdTranslate;
+            stransforms['-webkit-transform'] += stdTranslate;
+            stransforms['-o-transform'] += stdTranslate;
+            stransforms['-ms-transform'] += stdTranslate;
+        }
+        if (degrees != 0) {
+            var rotation = degrees / 90;
+            var stdRotate = ' rotate(' + degrees + 'deg)';
+            stransforms['-moz-transform'] += stdRotate;
+            stransforms['-webkit-transform'] += stdRotate;
+            stransforms['-o-transform'] += stdRotate;
+            stransforms['-ms-transform'] += stdRotate;
+        }
+        var s = 'top: 0; left: 0; ';
+        for (var prop in stransforms) {
+            if (stransforms[prop]) {
+                s += prop + ':' + stransforms[prop] + ';';
+            }
+        }
+        s += ';';
+        return s;
+    };
+
+    CssTransformAxisLabel.prototype.calculateOffsets = function(box) {
+        var offsets = { x: 0, y: 0, degrees: 0 };
+        if (this.position == 'bottom') {
+            offsets.x = box.left + box.width/2 - this.labelWidth/2;
+            offsets.y = box.top + box.height - this.labelHeight;
+        } else if (this.position == 'top') {
+            offsets.x = box.left + box.width/2 - this.labelWidth/2;
+            offsets.y = box.top;
+        } else if (this.position == 'left') {
+            offsets.degrees = -90;
+            offsets.x = box.left - this.labelWidth/2 + this.labelHeight/2;
+            offsets.y = box.height/2 + box.top;
+        } else if (this.position == 'right') {
+            offsets.degrees = 90;
+            offsets.x = box.left + box.width - this.labelWidth/2
+                        - this.labelHeight/2;
+            offsets.y = box.height/2 + box.top;
+        }
+        offsets.x = Math.round(offsets.x);
+        offsets.y = Math.round(offsets.y);
+
+        return offsets;
+    };
+
+    CssTransformAxisLabel.prototype.draw = function(box) {
+        this.plot.getPlaceholder().find("." + this.axisName + "Label").remove();
+        var offsets = this.calculateOffsets(box);
+        this.elem = $('<div class="axisLabels ' + this.axisName +
+                      'Label" style="position:absolute; ' +
+                      this.transforms(offsets.degrees, offsets.x, offsets.y) +
+                      '">' + this.opts.axisLabel + '</div>');
+        this.plot.getPlaceholder().append(this.elem);
+    };
+
+
+    IeTransformAxisLabel.prototype = new CssTransformAxisLabel();
+    IeTransformAxisLabel.prototype.constructor = IeTransformAxisLabel;
+    function IeTransformAxisLabel(axisName, position, padding, plot, opts) {
+        CssTransformAxisLabel.prototype.constructor.call(this, axisName,
+                                                         position, padding,
+                                                         plot, opts);
+        this.requiresResize = false;
+    }
+
+    IeTransformAxisLabel.prototype.transforms = function(degrees, x, y) {
+        // I didn't feel like learning the crazy Matrix stuff, so this uses
+        // a combination of the rotation transform and CSS positioning.
+        var s = '';
+        if (degrees != 0) {
+            var rotation = degrees/90;
+            while (rotation < 0) {
+                rotation += 4;
+            }
+            s += ' filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=' + rotation + '); ';
+            // see below
+            this.requiresResize = (this.position == 'right');
+        }
+        if (x != 0) {
+            s += 'left: ' + x + 'px; ';
+        }
+        if (y != 0) {
+            s += 'top: ' + y + 'px; ';
+        }
+        return s;
+    };
+
+    IeTransformAxisLabel.prototype.calculateOffsets = function(box) {
+        var offsets = CssTransformAxisLabel.prototype.calculateOffsets.call(
+                          this, box);
+        // adjust some values to take into account differences between
+        // CSS and IE rotations.
+        if (this.position == 'top') {
+            // FIXME: not sure why, but placing this exactly at the top causes
+            // the top axis label to flip to the bottom...
+            offsets.y = box.top + 1;
+        } else if (this.position == 'left') {
+            offsets.x = box.left;
+            offsets.y = box.height/2 + box.top - this.labelWidth/2;
+        } else if (this.position == 'right') {
+            offsets.x = box.left + box.width - this.labelHeight;
+            offsets.y = box.height/2 + box.top - this.labelWidth/2;
+        }
+        return offsets;
+    };
+
+    IeTransformAxisLabel.prototype.draw = function(box) {
+        CssTransformAxisLabel.prototype.draw.call(this, box);
+        if (this.requiresResize) {
+            this.elem = this.plot.getPlaceholder().find("." + this.axisName +
+                                                        "Label");
+            // Since we used CSS positioning instead of transforms for
+            // translating the element, and since the positioning is done
+            // before any rotations, we have to reset the width and height
+            // in case the browser wrapped the text (specifically for the
+            // y2axis).
+            this.elem.css('width', this.labelWidth);
+            this.elem.css('height', this.labelHeight);
+        }
+    };
+
+
+    function init(plot) {
+        plot.hooks.processOptions.push(function (plot, options) {
+
+            if (!options.axisLabels.show)
+                return;
+
+            // This is kind of a hack. There are no hooks in Flot between
+            // the creation and measuring of the ticks (setTicks, measureTickLabels
+            // in setupGrid() ) and the drawing of the ticks and plot box
+            // (insertAxisLabels in setupGrid() ).
+            //
+            // Therefore, we use a trick where we run the draw routine twice:
+            // the first time to get the tick measurements, so that we can change
+            // them, and then have it draw it again.
+            var secondPass = false;
+
+            var axisLabels = {};
+            var axisOffsetCounts = { left: 0, right: 0, top: 0, bottom: 0 };
+
+            var defaultPadding = 2;  // padding between axis and tick labels
+            plot.hooks.draw.push(function (plot, ctx) {
+                var hasAxisLabels = false;
+                if (!secondPass) {
+                    // MEASURE AND SET OPTIONS
+                    $.each(plot.getAxes(), function(axisName, axis) {
+                        var opts = axis.options // Flot 0.7
+                            || plot.getOptions()[axisName]; // Flot 0.6
+
+                        // Handle redraws initiated outside of this plug-in.
+                        if (axisName in axisLabels) {
+                            axis.labelHeight = axis.labelHeight -
+                                axisLabels[axisName].height;
+                            axis.labelWidth = axis.labelWidth -
+                                axisLabels[axisName].width;
+                            opts.labelHeight = axis.labelHeight;
+                            opts.labelWidth = axis.labelWidth;
+                            axisLabels[axisName].cleanup();
+                            delete axisLabels[axisName];
+                        }
+
+                        if (!opts || !opts.axisLabel || !axis.show)
+                            return;
+
+                        hasAxisLabels = true;
+                        var renderer = null;
+
+                        if (!opts.axisLabelUseHtml &&
+                            navigator.appName == 'Microsoft Internet Explorer') {
+                            var ua = navigator.userAgent;
+                            var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
+                            if (re.exec(ua) != null) {
+                                rv = parseFloat(RegExp.$1);
+                            }
+                            if (rv >= 9 && !opts.axisLabelUseCanvas && !opts.axisLabelUseHtml) {
+                                renderer = CssTransformAxisLabel;
+                            } else if (!opts.axisLabelUseCanvas && !opts.axisLabelUseHtml) {
+                                renderer = IeTransformAxisLabel;
+                            } else if (opts.axisLabelUseCanvas) {
+                                renderer = CanvasAxisLabel;
+                            } else {
+                                renderer = HtmlAxisLabel;
+                            }
+                        } else {
+                            if (opts.axisLabelUseHtml || (!css3TransitionSupported() && !canvasTextSupported()) && !opts.axisLabelUseCanvas) {
+                                renderer = HtmlAxisLabel;
+                            } else if (opts.axisLabelUseCanvas || !css3TransitionSupported()) {
+                                renderer = CanvasAxisLabel;
+                            } else {
+                                renderer = CssTransformAxisLabel;
+                            }
+                        }
+
+                        var padding = opts.axisLabelPadding === undefined ?
+                                      defaultPadding : opts.axisLabelPadding;
+
+                        axisLabels[axisName] = new renderer(axisName,
+                                                            axis.position, padding,
+                                                            plot, opts);
+
+                        // flot interprets axis.labelHeight and .labelWidth as
+                        // the height and width of the tick labels. We increase
+                        // these values to make room for the axis label and
+                        // padding.
+
+                        axisLabels[axisName].calculateSize();
+
+                        // AxisLabel.height and .width are the size of the
+                        // axis label and padding.
+                        // Just set opts here because axis will be sorted out on
+                        // the redraw.
+
+                        opts.labelHeight = axis.labelHeight +
+                            axisLabels[axisName].height;
+                        opts.labelWidth = axis.labelWidth +
+                            axisLabels[axisName].width;
+                    });
+
+                    // If there are axis labels, re-draw with new label widths and
+                    // heights.
+
+                    if (hasAxisLabels) {
+                        secondPass = true;
+                        plot.setupGrid();
+                        plot.draw();
+                    }
+                } else {
+                    secondPass = false;
+                    // DRAW
+                    $.each(plot.getAxes(), function(axisName, axis) {
+                        var opts = axis.options // Flot 0.7
+                            || plot.getOptions()[axisName]; // Flot 0.6
+                        if (!opts || !opts.axisLabel || !axis.show)
+                            return;
+
+                        axisLabels[axisName].draw(axis.box);
+                    });
+                }
+            });
+        });
+    }
+
+
+    $.plot.plugins.push({
+        init: init,
+        options: options,
+        name: 'axisLabels',
+        version: '2.0'
+    });
+})(jQuery);
diff --git a/js/jquery.flot.js b/js/jquery.flot.js
new file mode 100644
index 0000000000000000000000000000000000000000..fd33fd20274d8e2b4c5a6134379e0389572f4e09
--- /dev/null
+++ b/js/jquery.flot.js
@@ -0,0 +1,3175 @@
+/* Javascript plotting library for jQuery, version 0.8.3.
+
+Copyright (c) 2007-2014 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+*/
+
+// first an inline dependency, jquery.colorhelpers.js, we inline it here
+// for convenience
+
+/* Plugin for jQuery for working with colors.
+ *
+ * Version 1.1.
+ *
+ * Inspiration from jQuery color animation plugin by John Resig.
+ *
+ * Released under the MIT license by Ole Laursen, October 2009.
+ *
+ * Examples:
+ *
+ *   $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
+ *   var c = $.color.extract($("#mydiv"), 'background-color');
+ *   console.log(c.r, c.g, c.b, c.a);
+ *   $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
+ *
+ * Note that .scale() and .add() return the same modified object
+ * instead of making a new one.
+ *
+ * V. 1.1: Fix error handling so e.g. parsing an empty string does
+ * produce a color rather than just crashing.
+ */
+(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);
+
+// the actual Flot code
+(function($) {
+
+	// Cache the prototype hasOwnProperty for faster access
+
+	var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+    // A shim to provide 'detach' to jQuery versions prior to 1.4.  Using a DOM
+    // operation produces the same effect as detach, i.e. removing the element
+    // without touching its jQuery data.
+
+    // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+.
+
+    if (!$.fn.detach) {
+        $.fn.detach = function() {
+            return this.each(function() {
+                if (this.parentNode) {
+                    this.parentNode.removeChild( this );
+                }
+            });
+        };
+    }
+
+	///////////////////////////////////////////////////////////////////////////
+	// The Canvas object is a wrapper around an HTML5 <canvas> tag.
+	//
+	// @constructor
+	// @param {string} cls List of classes to apply to the canvas.
+	// @param {element} container Element onto which to append the canvas.
+	//
+	// Requiring a container is a little iffy, but unfortunately canvas
+	// operations don't work unless the canvas is attached to the DOM.
+
+	function Canvas(cls, container) {
+
+		var element = container.children("." + cls)[0];
+
+		if (element == null) {
+
+			element = document.createElement("canvas");
+			element.className = cls;
+
+			$(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 })
+				.appendTo(container);
+
+			// If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas
+
+			if (!element.getContext) {
+				if (window.G_vmlCanvasManager) {
+					element = window.G_vmlCanvasManager.initElement(element);
+				} else {
+					throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.");
+				}
+			}
+		}
+
+		this.element = element;
+
+		var context = this.context = element.getContext("2d");
+
+		// Determine the screen's ratio of physical to device-independent
+		// pixels.  This is the ratio between the canvas width that the browser
+		// advertises and the number of pixels actually present in that space.
+
+		// The iPhone 4, for example, has a device-independent width of 320px,
+		// but its screen is actually 640px wide.  It therefore has a pixel
+		// ratio of 2, while most normal devices have a ratio of 1.
+
+		var devicePixelRatio = window.devicePixelRatio || 1,
+			backingStoreRatio =
+				context.webkitBackingStorePixelRatio ||
+				context.mozBackingStorePixelRatio ||
+				context.msBackingStorePixelRatio ||
+				context.oBackingStorePixelRatio ||
+				context.backingStorePixelRatio || 1;
+
+		this.pixelRatio = devicePixelRatio / backingStoreRatio;
+
+		// Size the canvas to match the internal dimensions of its container
+
+		this.resize(container.width(), container.height());
+
+		// Collection of HTML div layers for text overlaid onto the canvas
+
+		this.textContainer = null;
+		this.text = {};
+
+		// Cache of text fragments and metrics, so we can avoid expensively
+		// re-calculating them when the plot is re-rendered in a loop.
+
+		this._textCache = {};
+	}
+
+	// Resizes the canvas to the given dimensions.
+	//
+	// @param {number} width New width of the canvas, in pixels.
+	// @param {number} width New height of the canvas, in pixels.
+
+	Canvas.prototype.resize = function(width, height) {
+
+		if (width <= 0 || height <= 0) {
+			throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height);
+		}
+
+		var element = this.element,
+			context = this.context,
+			pixelRatio = this.pixelRatio;
+
+		// Resize the canvas, increasing its density based on the display's
+		// pixel ratio; basically giving it more pixels without increasing the
+		// size of its element, to take advantage of the fact that retina
+		// displays have that many more pixels in the same advertised space.
+
+		// Resizing should reset the state (excanvas seems to be buggy though)
+
+		if (this.width != width) {
+			element.width = width * pixelRatio;
+			element.style.width = width + "px";
+			this.width = width;
+		}
+
+		if (this.height != height) {
+			element.height = height * pixelRatio;
+			element.style.height = height + "px";
+			this.height = height;
+		}
+
+		// Save the context, so we can reset in case we get replotted.  The
+		// restore ensure that we're really back at the initial state, and
+		// should be safe even if we haven't saved the initial state yet.
+
+		context.restore();
+		context.save();
+
+		// Scale the coordinate space to match the display density; so even though we
+		// may have twice as many pixels, we still want lines and other drawing to
+		// appear at the same size; the extra pixels will just make them crisper.
+
+		context.scale(pixelRatio, pixelRatio);
+	};
+
+	// Clears the entire canvas area, not including any overlaid HTML text
+
+	Canvas.prototype.clear = function() {
+		this.context.clearRect(0, 0, this.width, this.height);
+	};
+
+	// Finishes rendering the canvas, including managing the text overlay.
+
+	Canvas.prototype.render = function() {
+
+		var cache = this._textCache;
+
+		// For each text layer, add elements marked as active that haven't
+		// already been rendered, and remove those that are no longer active.
+
+		for (var layerKey in cache) {
+			if (hasOwnProperty.call(cache, layerKey)) {
+
+				var layer = this.getTextLayer(layerKey),
+					layerCache = cache[layerKey];
+
+				layer.hide();
+
+				for (var styleKey in layerCache) {
+					if (hasOwnProperty.call(layerCache, styleKey)) {
+						var styleCache = layerCache[styleKey];
+						for (var key in styleCache) {
+							if (hasOwnProperty.call(styleCache, key)) {
+
+								var positions = styleCache[key].positions;
+
+								for (var i = 0, position; position = positions[i]; i++) {
+									if (position.active) {
+										if (!position.rendered) {
+											layer.append(position.element);
+											position.rendered = true;
+										}
+									} else {
+										positions.splice(i--, 1);
+										if (position.rendered) {
+											position.element.detach();
+										}
+									}
+								}
+
+								if (positions.length == 0) {
+									delete styleCache[key];
+								}
+							}
+						}
+					}
+				}
+
+				layer.show();
+			}
+		}
+	};
+
+	// Creates (if necessary) and returns the text overlay container.
+	//
+	// @param {string} classes String of space-separated CSS classes used to
+	//     uniquely identify the text layer.
+	// @return {object} The jQuery-wrapped text-layer div.
+
+	Canvas.prototype.getTextLayer = function(classes) {
+
+		var layer = this.text[classes];
+
+		// Create the text layer if it doesn't exist
+
+		if (layer == null) {
+
+			// Create the text layer container, if it doesn't exist
+
+			if (this.textContainer == null) {
+				this.textContainer = $("<div class='flot-text'></div>")
+					.css({
+						position: "absolute",
+						top: 0,
+						left: 0,
+						bottom: 0,
+						right: 0,
+						'font-size': "smaller",
+						color: "#545454"
+					})
+					.insertAfter(this.element);
+			}
+
+			layer = this.text[classes] = $("<div></div>")
+				.addClass(classes)
+				.css({
+					position: "absolute",
+					top: 0,
+					left: 0,
+					bottom: 0,
+					right: 0
+				})
+				.appendTo(this.textContainer);
+		}
+
+		return layer;
+	};
+
+	// Creates (if necessary) and returns a text info object.
+	//
+	// The object looks like this:
+	//
+	// {
+	//     width: Width of the text's wrapper div.
+	//     height: Height of the text's wrapper div.
+	//     element: The jQuery-wrapped HTML div containing the text.
+	//     positions: Array of positions at which this text is drawn.
+	// }
+	//
+	// The positions array contains objects that look like this:
+	//
+	// {
+	//     active: Flag indicating whether the text should be visible.
+	//     rendered: Flag indicating whether the text is currently visible.
+	//     element: The jQuery-wrapped HTML div containing the text.
+	//     x: X coordinate at which to draw the text.
+	//     y: Y coordinate at which to draw the text.
+	// }
+	//
+	// Each position after the first receives a clone of the original element.
+	//
+	// The idea is that that the width, height, and general 'identity' of the
+	// text is constant no matter where it is placed; the placements are a
+	// secondary property.
+	//
+	// Canvas maintains a cache of recently-used text info objects; getTextInfo
+	// either returns the cached element or creates a new entry.
+	//
+	// @param {string} layer A string of space-separated CSS classes uniquely
+	//     identifying the layer containing this text.
+	// @param {string} text Text string to retrieve info for.
+	// @param {(string|object)=} font Either a string of space-separated CSS
+	//     classes or a font-spec object, defining the text's font and style.
+	// @param {number=} angle Angle at which to rotate the text, in degrees.
+	//     Angle is currently unused, it will be implemented in the future.
+	// @param {number=} width Maximum width of the text before it wraps.
+	// @return {object} a text info object.
+
+	Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) {
+
+		var textStyle, layerCache, styleCache, info;
+
+		// Cast the value to a string, in case we were given a number or such
+
+		text = "" + text;
+
+		// If the font is a font-spec object, generate a CSS font definition
+
+		if (typeof font === "object") {
+			textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family;
+		} else {
+			textStyle = font;
+		}
+
+		// Retrieve (or create) the cache for the text's layer and styles
+
+		layerCache = this._textCache[layer];
+
+		if (layerCache == null) {
+			layerCache = this._textCache[layer] = {};
+		}
+
+		styleCache = layerCache[textStyle];
+
+		if (styleCache == null) {
+			styleCache = layerCache[textStyle] = {};
+		}
+
+		info = styleCache[text];
+
+		// If we can't find a matching element in our cache, create a new one
+
+		if (info == null) {
+
+			var element = $("<div></div>").html(text)
+				.css({
+					position: "absolute",
+					'max-width': width,
+					top: -9999
+				})
+				.appendTo(this.getTextLayer(layer));
+
+			if (typeof font === "object") {
+				element.css({
+					font: textStyle,
+					color: font.color
+				});
+			} else if (typeof font === "string") {
+				element.addClass(font);
+			}
+
+			info = styleCache[text] = {
+				width: element.outerWidth(true),
+				height: element.outerHeight(true),
+				element: element,
+				positions: []
+			};
+
+			element.detach();
+		}
+
+		return info;
+	};
+
+	// Adds a text string to the canvas text overlay.
+	//
+	// The text isn't drawn immediately; it is marked as rendering, which will
+	// result in its addition to the canvas on the next render pass.
+	//
+	// @param {string} layer A string of space-separated CSS classes uniquely
+	//     identifying the layer containing this text.
+	// @param {number} x X coordinate at which to draw the text.
+	// @param {number} y Y coordinate at which to draw the text.
+	// @param {string} text Text string to draw.
+	// @param {(string|object)=} font Either a string of space-separated CSS
+	//     classes or a font-spec object, defining the text's font and style.
+	// @param {number=} angle Angle at which to rotate the text, in degrees.
+	//     Angle is currently unused, it will be implemented in the future.
+	// @param {number=} width Maximum width of the text before it wraps.
+	// @param {string=} halign Horizontal alignment of the text; either "left",
+	//     "center" or "right".
+	// @param {string=} valign Vertical alignment of the text; either "top",
+	//     "middle" or "bottom".
+
+	Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) {
+
+		var info = this.getTextInfo(layer, text, font, angle, width),
+			positions = info.positions;
+
+		// Tweak the div's position to match the text's alignment
+
+		if (halign == "center") {
+			x -= info.width / 2;
+		} else if (halign == "right") {
+			x -= info.width;
+		}
+
+		if (valign == "middle") {
+			y -= info.height / 2;
+		} else if (valign == "bottom") {
+			y -= info.height;
+		}
+
+		// Determine whether this text already exists at this position.
+		// If so, mark it for inclusion in the next render pass.
+
+		for (var i = 0, position; position = positions[i]; i++) {
+			if (position.x == x && position.y == y) {
+				position.active = true;
+				return;
+			}
+		}
+
+		// If the text doesn't exist at this position, create a new entry
+
+		// For the very first position we'll re-use the original element,
+		// while for subsequent ones we'll clone it.
+
+		position = {
+			active: true,
+			rendered: false,
+			element: positions.length ? info.element.clone() : info.element,
+			x: x,
+			y: y
+		};
+
+		positions.push(position);
+
+		// Move the element to its final position within the container
+
+		position.element.css({
+			top: Math.round(y),
+			left: Math.round(x),
+			'text-align': halign	// In case the text wraps
+		});
+	};
+
+	// Removes one or more text strings from the canvas text overlay.
+	//
+	// If no parameters are given, all text within the layer is removed.
+	//
+	// Note that the text is not immediately removed; it is simply marked as
+	// inactive, which will result in its removal on the next render pass.
+	// This avoids the performance penalty for 'clear and redraw' behavior,
+	// where we potentially get rid of all text on a layer, but will likely
+	// add back most or all of it later, as when redrawing axes, for example.
+	//
+	// @param {string} layer A string of space-separated CSS classes uniquely
+	//     identifying the layer containing this text.
+	// @param {number=} x X coordinate of the text.
+	// @param {number=} y Y coordinate of the text.
+	// @param {string=} text Text string to remove.
+	// @param {(string|object)=} font Either a string of space-separated CSS
+	//     classes or a font-spec object, defining the text's font and style.
+	// @param {number=} angle Angle at which the text is rotated, in degrees.
+	//     Angle is currently unused, it will be implemented in the future.
+
+	Canvas.prototype.removeText = function(layer, x, y, text, font, angle) {
+		if (text == null) {
+			var layerCache = this._textCache[layer];
+			if (layerCache != null) {
+				for (var styleKey in layerCache) {
+					if (hasOwnProperty.call(layerCache, styleKey)) {
+						var styleCache = layerCache[styleKey];
+						for (var key in styleCache) {
+							if (hasOwnProperty.call(styleCache, key)) {
+								var positions = styleCache[key].positions;
+								for (var i = 0, position; position = positions[i]; i++) {
+									position.active = false;
+								}
+							}
+						}
+					}
+				}
+			}
+		} else {
+			var positions = this.getTextInfo(layer, text, font, angle).positions;
+			for (var i = 0, position; position = positions[i]; i++) {
+				if (position.x == x && position.y == y) {
+					position.active = false;
+				}
+			}
+		}
+	};
+
+	///////////////////////////////////////////////////////////////////////////
+	// The top-level container for the entire plot.
+
+    function Plot(placeholder, data_, options_, plugins) {
+        // data is on the form:
+        //   [ series1, series2 ... ]
+        // where series is either just the data as [ [x1, y1], [x2, y2], ... ]
+        // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... }
+
+        var series = [],
+            options = {
+                // the color theme used for graphs
+                colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"],
+                legend: {
+                    show: true,
+                    noColumns: 1, // number of colums in legend table
+                    labelFormatter: null, // fn: string -> string
+                    labelBoxBorderColor: "#ccc", // border color for the little label boxes
+                    container: null, // container (as jQuery object) to put legend in, null means default on top of graph
+                    position: "ne", // position of default legend container within plot
+                    margin: 5, // distance from grid edge to default legend container within plot
+                    backgroundColor: null, // null means auto-detect
+                    backgroundOpacity: 0.85, // set to 0 to avoid background
+                    sorted: null    // default to no legend sorting
+                },
+                xaxis: {
+                    show: null, // null = auto-detect, true = always, false = never
+                    position: "bottom", // or "top"
+                    mode: null, // null or "time"
+                    font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" }
+                    color: null, // base color, labels, ticks
+                    tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)"
+                    transform: null, // null or f: number -> number to transform axis
+                    inverseTransform: null, // if transform is set, this should be the inverse function
+                    min: null, // min. value to show, null means set automatically
+                    max: null, // max. value to show, null means set automatically
+                    autoscaleMargin: null, // margin in % to add if auto-setting min/max
+                    ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks
+                    tickFormatter: null, // fn: number -> string
+                    labelWidth: null, // size of tick labels in pixels
+                    labelHeight: null,
+                    reserveSpace: null, // whether to reserve space even if axis isn't shown
+                    tickLength: null, // size in pixels of ticks, or "full" for whole line
+                    alignTicksWithAxis: null, // axis number or null for no sync
+                    tickDecimals: null, // no. of decimals, null means auto
+                    tickSize: null, // number or [number, "unit"]
+                    minTickSize: null // number or [number, "unit"]
+                },
+                yaxis: {
+                    autoscaleMargin: 0.02,
+                    position: "left" // or "right"
+                },
+                xaxes: [],
+                yaxes: [],
+                series: {
+                    points: {
+                        show: false,
+                        radius: 3,
+                        lineWidth: 2, // in pixels
+                        fill: true,
+                        fillColor: "#ffffff",
+                        symbol: "circle" // or callback
+                    },
+                    lines: {
+                        // we don't put in show: false so we can see
+                        // whether lines were actively disabled
+                        lineWidth: 2, // in pixels
+                        fill: false,
+                        fillColor: null,
+                        steps: false
+                        // Omit 'zero', so we can later default its value to
+                        // match that of the 'fill' option.
+                    },
+                    bars: {
+                        show: false,
+                        lineWidth: 2, // in pixels
+                        barWidth: 1, // in units of the x axis
+                        fill: true,
+                        fillColor: null,
+                        align: "left", // "left", "right", or "center"
+                        horizontal: false,
+                        zero: true
+                    },
+                    shadowSize: 3,
+                    highlightColor: null
+                },
+                grid: {
+                    show: true,
+                    aboveData: false,
+                    color: "#545454", // primary color used for outline and labels
+                    backgroundColor: null, // null for transparent, else color
+                    borderColor: null, // set if different from the grid color
+                    tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)"
+                    margin: 0, // distance from the canvas edge to the grid
+                    labelMargin: 5, // in pixels
+                    axisMargin: 8, // in pixels
+                    borderWidth: 2, // in pixels
+                    minBorderMargin: null, // in pixels, null means taken from points radius
+                    markings: null, // array of ranges or fn: axes -> array of ranges
+                    markingsColor: "#f4f4f4",
+                    markingsLineWidth: 2,
+                    TickLineStyle: "dashed",
+                    // interactive stuff
+                    clickable: false,
+                    hoverable: false,
+                    autoHighlight: true, // highlight in case mouse is near
+                    mouseActiveRadius: 10 // how far the mouse can be away to activate an item
+                },
+                interaction: {
+                    redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow
+                },
+                hooks: {}
+            },
+        surface = null,     // the canvas for the plot itself
+        overlay = null,     // canvas for interactive stuff on top of plot
+        eventHolder = null, // jQuery object that events should be bound to
+        ctx = null, octx = null,
+        xaxes = [], yaxes = [],
+        plotOffset = { left: 0, right: 0, top: 0, bottom: 0},
+        plotWidth = 0, plotHeight = 0,
+        hooks = {
+            processOptions: [],
+            processRawData: [],
+            processDatapoints: [],
+            processOffset: [],
+            drawBackground: [],
+            drawSeries: [],
+            draw: [],
+            bindEvents: [],
+            drawOverlay: [],
+            shutdown: []
+        },
+        plot = this;
+
+        // public functions
+        plot.setData = setData;
+        plot.setupGrid = setupGrid;
+        plot.draw = draw;
+        plot.getPlaceholder = function() { return placeholder; };
+        plot.getCanvas = function() { return surface.element; };
+        plot.getPlotOffset = function() { return plotOffset; };
+        plot.width = function () { return plotWidth; };
+        plot.height = function () { return plotHeight; };
+        plot.offset = function () {
+            var o = eventHolder.offset();
+            o.left += plotOffset.left;
+            o.top += plotOffset.top;
+            return o;
+        };
+        plot.getData = function () { return series; };
+        plot.getAxes = function () {
+            var res = {}, i;
+            $.each(xaxes.concat(yaxes), function (_, axis) {
+                if (axis)
+                    res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis;
+            });
+            return res;
+        };
+        plot.getXAxes = function () { return xaxes; };
+        plot.getYAxes = function () { return yaxes; };
+        plot.c2p = canvasToAxisCoords;
+        plot.p2c = axisToCanvasCoords;
+        plot.getOptions = function () { return options; };
+        plot.highlight = highlight;
+        plot.unhighlight = unhighlight;
+        plot.triggerRedrawOverlay = triggerRedrawOverlay;
+        plot.pointOffset = function(point) {
+            return {
+                left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10),
+                top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10)
+            };
+        };
+        plot.shutdown = shutdown;
+        plot.destroy = function () {
+            shutdown();
+            placeholder.removeData("plot").empty();
+
+            series = [];
+            options = null;
+            surface = null;
+            overlay = null;
+            eventHolder = null;
+            ctx = null;
+            octx = null;
+            xaxes = [];
+            yaxes = [];
+            hooks = null;
+            highlights = [];
+            plot = null;
+        };
+        plot.resize = function () {
+        	var width = placeholder.width(),
+        		height = placeholder.height();
+            surface.resize(width, height);
+            overlay.resize(width, height);
+        };
+
+        // public attributes
+        plot.hooks = hooks;
+
+        // initialize
+        initPlugins(plot);
+        parseOptions(options_);
+        setupCanvases();
+        setData(data_);
+        setupGrid();
+        draw();
+        bindEvents();
+
+
+        function executeHooks(hook, args) {
+            args = [plot].concat(args);
+            for (var i = 0; i < hook.length; ++i)
+                hook[i].apply(this, args);
+        }
+
+        function initPlugins() {
+
+            // References to key classes, allowing plugins to modify them
+
+            var classes = {
+                Canvas: Canvas
+            };
+
+            for (var i = 0; i < plugins.length; ++i) {
+                var p = plugins[i];
+                p.init(plot, classes);
+                if (p.options)
+                    $.extend(true, options, p.options);
+            }
+        }
+
+        function parseOptions(opts) {
+
+            $.extend(true, options, opts);
+
+            // $.extend merges arrays, rather than replacing them.  When less
+            // colors are provided than the size of the default palette, we
+            // end up with those colors plus the remaining defaults, which is
+            // not expected behavior; avoid it by replacing them here.
+
+            if (opts && opts.colors) {
+            	options.colors = opts.colors;
+            }
+
+            if (options.xaxis.color == null)
+                options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();
+            if (options.yaxis.color == null)
+                options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();
+
+            if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility
+                options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color;
+            if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility
+                options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color;
+
+            if (options.grid.borderColor == null)
+                options.grid.borderColor = options.grid.color;
+            if (options.grid.tickColor == null)
+                options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();
+
+            // Fill in defaults for axis options, including any unspecified
+            // font-spec fields, if a font-spec was provided.
+
+            // If no x/y axis options were provided, create one of each anyway,
+            // since the rest of the code assumes that they exist.
+
+            var i, axisOptions, axisCount,
+                fontSize = placeholder.css("font-size"),
+                fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 14,
+                fontDefaults = {
+                    style: placeholder.css("font-style"),
+                    size: Math.round(0.8 * fontSizeDefault),
+                    variant: placeholder.css("font-variant"),
+                    weight: placeholder.css("font-weight"),
+                    family: placeholder.css("font-family")
+                };
+
+            axisCount = options.xaxes.length || 1;
+            for (i = 0; i < axisCount; ++i) {
+
+                axisOptions = options.xaxes[i];
+                if (axisOptions && !axisOptions.tickColor) {
+                    axisOptions.tickColor = axisOptions.color;
+                }
+
+                axisOptions = $.extend(true, {}, options.xaxis, axisOptions);
+                options.xaxes[i] = axisOptions;
+
+                if (axisOptions.font) {
+                    axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);
+                    if (!axisOptions.font.color) {
+                        axisOptions.font.color = axisOptions.color;
+                    }
+                    if (!axisOptions.font.lineHeight) {
+                        axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
+                    }
+                }
+            }
+
+            axisCount = options.yaxes.length || 1;
+            for (i = 0; i < axisCount; ++i) {
+
+                axisOptions = options.yaxes[i];
+                if (axisOptions && !axisOptions.tickColor) {
+                    axisOptions.tickColor = axisOptions.color;
+                }
+
+                axisOptions = $.extend(true, {}, options.yaxis, axisOptions);
+                options.yaxes[i] = axisOptions;
+
+                if (axisOptions.font) {
+                    axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);
+                    if (!axisOptions.font.color) {
+                        axisOptions.font.color = axisOptions.color;
+                    }
+                    if (!axisOptions.font.lineHeight) {
+                        axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
+                    }
+                }
+            }
+
+            // backwards compatibility, to be removed in future
+            if (options.xaxis.noTicks && options.xaxis.ticks == null)
+                options.xaxis.ticks = options.xaxis.noTicks;
+            if (options.yaxis.noTicks && options.yaxis.ticks == null)
+                options.yaxis.ticks = options.yaxis.noTicks;
+            if (options.x2axis) {
+                options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);
+                options.xaxes[1].position = "top";
+                // Override the inherit to allow the axis to auto-scale
+                if (options.x2axis.min == null) {
+                    options.xaxes[1].min = null;
+                }
+                if (options.x2axis.max == null) {
+                    options.xaxes[1].max = null;
+                }
+            }
+            if (options.y2axis) {
+                options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);
+                options.yaxes[1].position = "right";
+                // Override the inherit to allow the axis to auto-scale
+                if (options.y2axis.min == null) {
+                    options.yaxes[1].min = null;
+                }
+                if (options.y2axis.max == null) {
+                    options.yaxes[1].max = null;
+                }
+            }
+            if (options.grid.coloredAreas)
+                options.grid.markings = options.grid.coloredAreas;
+            if (options.grid.coloredAreasColor)
+                options.grid.markingsColor = options.grid.coloredAreasColor;
+            if (options.lines)
+                $.extend(true, options.series.lines, options.lines);
+            if (options.points)
+                $.extend(true, options.series.points, options.points);
+            if (options.bars)
+                $.extend(true, options.series.bars, options.bars);
+            if (options.shadowSize != null)
+                options.series.shadowSize = options.shadowSize;
+            if (options.highlightColor != null)
+                options.series.highlightColor = options.highlightColor;
+
+            // save options on axes for future reference
+            for (i = 0; i < options.xaxes.length; ++i)
+                getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i];
+            for (i = 0; i < options.yaxes.length; ++i)
+                getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i];
+
+            // add hooks from options
+            for (var n in hooks)
+                if (options.hooks[n] && options.hooks[n].length)
+                    hooks[n] = hooks[n].concat(options.hooks[n]);
+
+            executeHooks(hooks.processOptions, [options]);
+        }
+
+        function setData(d) {
+            series = parseData(d);
+            fillInSeriesOptions();
+            processData();
+        }
+
+        function parseData(d) {
+            var res = [];
+            for (var i = 0; i < d.length; ++i) {
+                var s = $.extend(true, {}, options.series);
+
+                if (d[i].data != null) {
+                    s.data = d[i].data; // move the data instead of deep-copy
+                    delete d[i].data;
+
+                    $.extend(true, s, d[i]);
+
+                    d[i].data = s.data;
+                }
+                else
+                    s.data = d[i];
+                res.push(s);
+            }
+
+            return res;
+        }
+
+        function axisNumber(obj, coord) {
+            var a = obj[coord + "axis"];
+            if (typeof a == "object") // if we got a real axis, extract number
+                a = a.n;
+            if (typeof a != "number")
+                a = 1; // default to first axis
+            return a;
+        }
+
+        function allAxes() {
+            // return flat array without annoying null entries
+            return $.grep(xaxes.concat(yaxes), function (a) { return a; });
+        }
+
+        function canvasToAxisCoords(pos) {
+            // return an object with x/y corresponding to all used axes
+            var res = {}, i, axis;
+            for (i = 0; i < xaxes.length; ++i) {
+                axis = xaxes[i];
+                if (axis && axis.used)
+                    res["x" + axis.n] = axis.c2p(pos.left);
+            }
+
+            for (i = 0; i < yaxes.length; ++i) {
+                axis = yaxes[i];
+                if (axis && axis.used)
+                    res["y" + axis.n] = axis.c2p(pos.top);
+            }
+
+            if (res.x1 !== undefined)
+                res.x = res.x1;
+            if (res.y1 !== undefined)
+                res.y = res.y1;
+
+            return res;
+        }
+
+        function axisToCanvasCoords(pos) {
+            // get canvas coords from the first pair of x/y found in pos
+            var res = {}, i, axis, key;
+
+            for (i = 0; i < xaxes.length; ++i) {
+                axis = xaxes[i];
+                if (axis && axis.used) {
+                    key = "x" + axis.n;
+                    if (pos[key] == null && axis.n == 1)
+                        key = "x";
+
+                    if (pos[key] != null) {
+                        res.left = axis.p2c(pos[key]);
+                        break;
+                    }
+                }
+            }
+
+            for (i = 0; i < yaxes.length; ++i) {
+                axis = yaxes[i];
+                if (axis && axis.used) {
+                    key = "y" + axis.n;
+                    if (pos[key] == null && axis.n == 1)
+                        key = "y";
+
+                    if (pos[key] != null) {
+                        res.top = axis.p2c(pos[key]);
+                        break;
+                    }
+                }
+            }
+
+            return res;
+        }
+
+        function getOrCreateAxis(axes, number) {
+            if (!axes[number - 1])
+                axes[number - 1] = {
+                    n: number, // save the number for future reference
+                    direction: axes == xaxes ? "x" : "y",
+                    options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)
+                };
+
+            return axes[number - 1];
+        }
+
+        function fillInSeriesOptions() {
+
+            var neededColors = series.length, maxIndex = -1, i;
+
+            // Subtract the number of series that already have fixed colors or
+            // color indexes from the number that we still need to generate.
+
+            for (i = 0; i < series.length; ++i) {
+                var sc = series[i].color;
+                if (sc != null) {
+                    neededColors--;
+                    if (typeof sc == "number" && sc > maxIndex) {
+                        maxIndex = sc;
+                    }
+                }
+            }
+
+            // If any of the series have fixed color indexes, then we need to
+            // generate at least as many colors as the highest index.
+
+            if (neededColors <= maxIndex) {
+                neededColors = maxIndex + 1;
+            }
+
+            // Generate all the colors, using first the option colors and then
+            // variations on those colors once they're exhausted.
+
+            var c, colors = [], colorPool = options.colors,
+                colorPoolSize = colorPool.length, variation = 0;
+
+            for (i = 0; i < neededColors; i++) {
+
+                c = $.color.parse(colorPool[i % colorPoolSize] || "#666");
+
+                // Each time we exhaust the colors in the pool we adjust
+                // a scaling factor used to produce more variations on
+                // those colors. The factor alternates negative/positive
+                // to produce lighter/darker colors.
+
+                // Reset the variation after every few cycles, or else
+                // it will end up producing only white or black colors.
+
+                if (i % colorPoolSize == 0 && i) {
+                    if (variation >= 0) {
+                        if (variation < 0.5) {
+                            variation = -variation - 0.2;
+                        } else variation = 0;
+                    } else variation = -variation;
+                }
+
+                colors[i] = c.scale('rgb', 1 + variation);
+            }
+
+            // Finalize the series options, filling in their colors
+
+            var colori = 0, s;
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+
+                // assign colors
+                if (s.color == null) {
+                    s.color = colors[colori].toString();
+                    ++colori;
+                }
+                else if (typeof s.color == "number")
+                    s.color = colors[s.color].toString();
+
+                // turn on lines automatically in case nothing is set
+                if (s.lines.show == null) {
+                    var v, show = true;
+                    for (v in s)
+                        if (s[v] && s[v].show) {
+                            show = false;
+                            break;
+                        }
+                    if (show)
+                        s.lines.show = true;
+                }
+
+                // If nothing was provided for lines.zero, default it to match
+                // lines.fill, since areas by default should extend to zero.
+
+                if (s.lines.zero == null) {
+                    s.lines.zero = !!s.lines.fill;
+                }
+
+                // setup axes
+                s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x"));
+                s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y"));
+            }
+        }
+
+        function processData() {
+            var topSentry = Number.POSITIVE_INFINITY,
+                bottomSentry = Number.NEGATIVE_INFINITY,
+                fakeInfinity = Number.MAX_VALUE,
+                i, j, k, m, length,
+                s, points, ps, x, y, axis, val, f, p,
+                data, format;
+
+            function updateAxis(axis, min, max) {
+                if (min < axis.datamin && min != -fakeInfinity)
+                    axis.datamin = min;
+                if (max > axis.datamax && max != fakeInfinity)
+                    axis.datamax = max;
+            }
+
+            $.each(allAxes(), function (_, axis) {
+                // init axis
+                axis.datamin = topSentry;
+                axis.datamax = bottomSentry;
+                axis.used = false;
+            });
+
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+                s.datapoints = { points: [] };
+
+                executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]);
+            }
+
+            // first pass: clean and copy data
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+
+                data = s.data;
+                format = s.datapoints.format;
+
+                if (!format) {
+                    format = [];
+                    // find out how to copy
+                    format.push({ x: true, number: true, required: true });
+                    format.push({ y: true, number: true, required: true });
+
+                    if (s.bars.show || (s.lines.show && s.lines.fill)) {
+                        var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero));
+                        format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale });
+                        if (s.bars.horizontal) {
+                            delete format[format.length - 1].y;
+                            format[format.length - 1].x = true;
+                        }
+                    }
+
+                    s.datapoints.format = format;
+                }
+
+                if (s.datapoints.pointsize != null)
+                    continue; // already filled in
+
+                s.datapoints.pointsize = format.length;
+
+                ps = s.datapoints.pointsize;
+                points = s.datapoints.points;
+
+                var insertSteps = s.lines.show && s.lines.steps;
+                s.xaxis.used = s.yaxis.used = true;
+
+                for (j = k = 0; j < data.length; ++j, k += ps) {
+                    p = data[j];
+
+                    var nullify = p == null;
+                    if (!nullify) {
+                        for (m = 0; m < ps; ++m) {
+                            val = p[m];
+                            f = format[m];
+
+                            if (f) {
+                                if (f.number && val != null) {
+                                    val = +val; // convert to number
+                                    if (isNaN(val))
+                                        val = null;
+                                    else if (val == Infinity)
+                                        val = fakeInfinity;
+                                    else if (val == -Infinity)
+                                        val = -fakeInfinity;
+                                }
+
+                                if (val == null) {
+                                    if (f.required)
+                                        nullify = true;
+
+                                    if (f.defaultValue != null)
+                                        val = f.defaultValue;
+                                }
+                            }
+
+                            points[k + m] = val;
+                        }
+                    }
+
+                    if (nullify) {
+                        for (m = 0; m < ps; ++m) {
+                            val = points[k + m];
+                            if (val != null) {
+                                f = format[m];
+                                // extract min/max info
+                                if (f.autoscale !== false) {
+                                    if (f.x) {
+                                        updateAxis(s.xaxis, val, val);
+                                    }
+                                    if (f.y) {
+                                        updateAxis(s.yaxis, val, val);
+                                    }
+                                }
+                            }
+                            points[k + m] = null;
+                        }
+                    }
+                    else {
+                        // a little bit of line specific stuff that
+                        // perhaps shouldn't be here, but lacking
+                        // better means...
+                        if (insertSteps && k > 0
+                            && points[k - ps] != null
+                            && points[k - ps] != points[k]
+                            && points[k - ps + 1] != points[k + 1]) {
+                            // copy the point to make room for a middle point
+                            for (m = 0; m < ps; ++m)
+                                points[k + ps + m] = points[k + m];
+
+                            // middle point has same y
+                            points[k + 1] = points[k - ps + 1];
+
+                            // we've added a point, better reflect that
+                            k += ps;
+                        }
+                    }
+                }
+            }
+
+            // give the hooks a chance to run
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+
+                executeHooks(hooks.processDatapoints, [ s, s.datapoints]);
+            }
+
+            // second pass: find datamax/datamin for auto-scaling
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+                points = s.datapoints.points;
+                ps = s.datapoints.pointsize;
+                format = s.datapoints.format;
+
+                var xmin = topSentry, ymin = topSentry,
+                    xmax = bottomSentry, ymax = bottomSentry;
+
+                for (j = 0; j < points.length; j += ps) {
+                    if (points[j] == null)
+                        continue;
+
+                    for (m = 0; m < ps; ++m) {
+                        val = points[j + m];
+                        f = format[m];
+                        if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity)
+                            continue;
+
+                        if (f.x) {
+                            if (val < xmin)
+                                xmin = val;
+                            if (val > xmax)
+                                xmax = val;
+                        }
+                        if (f.y) {
+                            if (val < ymin)
+                                ymin = val;
+                            if (val > ymax)
+                                ymax = val;
+                        }
+                    }
+                }
+
+                if (s.bars.show) {
+                    // make sure we got room for the bar on the dancing floor
+                    var delta;
+
+                    switch (s.bars.align) {
+                        case "left":
+                            delta = 0;
+                            break;
+                        case "right":
+                            delta = -s.bars.barWidth;
+                            break;
+                        default:
+                            delta = -s.bars.barWidth / 2;
+                    }
+
+                    if (s.bars.horizontal) {
+                        ymin += delta;
+                        ymax += delta + s.bars.barWidth;
+                    }
+                    else {
+                        xmin += delta;
+                        xmax += delta + s.bars.barWidth;
+                    }
+                }
+
+                updateAxis(s.xaxis, xmin, xmax);
+                updateAxis(s.yaxis, ymin, ymax);
+            }
+
+            $.each(allAxes(), function (_, axis) {
+                if (axis.datamin == topSentry)
+                    axis.datamin = null;
+                if (axis.datamax == bottomSentry)
+                    axis.datamax = null;
+            });
+        }
+
+        function setupCanvases() {
+
+            // Make sure the placeholder is clear of everything except canvases
+            // from a previous plot in this container that we'll try to re-use.
+
+            placeholder.css("padding", 0) // padding messes up the positioning
+                .children().filter(function(){
+                    return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base');
+                }).remove();
+
+            if (placeholder.css("position") == 'static')
+                placeholder.css("position", "relative"); // for positioning labels and overlay
+
+            surface = new Canvas("flot-base", placeholder);
+            overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features
+
+            ctx = surface.context;
+            octx = overlay.context;
+
+            // define which element we're listening for events on
+            eventHolder = $(overlay.element).unbind();
+
+            // If we're re-using a plot object, shut down the old one
+
+            var existing = placeholder.data("plot");
+
+            if (existing) {
+                existing.shutdown();
+                overlay.clear();
+            }
+
+            // save in case we get replotted
+            placeholder.data("plot", plot);
+        }
+
+        function bindEvents() {
+            // bind events
+            if (options.grid.hoverable) {
+                eventHolder.mousemove(onMouseMove);
+
+                // Use bind, rather than .mouseleave, because we officially
+                // still support jQuery 1.2.6, which doesn't define a shortcut
+                // for mouseenter or mouseleave.  This was a bug/oversight that
+                // was fixed somewhere around 1.3.x.  We can return to using
+                // .mouseleave when we drop support for 1.2.6.
+
+                eventHolder.bind("mouseleave", onMouseLeave);
+            }
+
+            if (options.grid.clickable)
+                eventHolder.click(onClick);
+
+            executeHooks(hooks.bindEvents, [eventHolder]);
+        }
+
+        function shutdown() {
+            if (redrawTimeout)
+                clearTimeout(redrawTimeout);
+
+            eventHolder.unbind("mousemove", onMouseMove);
+            eventHolder.unbind("mouseleave", onMouseLeave);
+            eventHolder.unbind("click", onClick);
+
+            executeHooks(hooks.shutdown, [eventHolder]);
+        }
+
+        function setTransformationHelpers(axis) {
+            // set helper functions on the axis, assumes plot area
+            // has been computed already
+
+            function identity(x) { return x; }
+
+            var s, m, t = axis.options.transform || identity,
+                it = axis.options.inverseTransform;
+
+            // precompute how much the axis is scaling a point
+            // in canvas space
+            if (axis.direction == "x") {
+                s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min));
+                m = Math.min(t(axis.max), t(axis.min));
+            }
+            else {
+                s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min));
+                s = -s;
+                m = Math.max(t(axis.max), t(axis.min));
+            }
+
+            // data point to canvas coordinate
+            if (t == identity) // slight optimization
+                axis.p2c = function (p) { return (p - m) * s; };
+            else
+                axis.p2c = function (p) { return (t(p) - m) * s; };
+            // canvas coordinate to data point
+            if (!it)
+                axis.c2p = function (c) { return m + c / s; };
+            else
+                axis.c2p = function (c) { return it(m + c / s); };
+        }
+
+        function measureTickLabels(axis) {
+
+            var opts = axis.options,
+                ticks = axis.ticks || [],
+                labelWidth = opts.labelWidth || 0,
+                labelHeight = opts.labelHeight || 0,
+                maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null),
+                legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
+                layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
+                font = opts.font || "flot-tick-label tickLabel";
+
+            for (var i = 0; i < ticks.length; ++i) {
+
+                var t = ticks[i];
+
+                if (!t.label)
+                    continue;
+
+                var info = surface.getTextInfo(layer, t.label, font, null, maxWidth);
+
+                labelWidth = Math.max(labelWidth, info.width);
+                labelHeight = Math.max(labelHeight, info.height);
+            }
+
+            axis.labelWidth = opts.labelWidth || labelWidth;
+            axis.labelHeight = opts.labelHeight || labelHeight;
+        }
+
+        function allocateAxisBoxFirstPhase(axis) {
+            // find the bounding box of the axis by looking at label
+            // widths/heights and ticks, make room by diminishing the
+            // plotOffset; this first phase only looks at one
+            // dimension per axis, the other dimension depends on the
+            // other axes so will have to wait
+
+            var lw = axis.labelWidth,
+                lh = axis.labelHeight,
+                pos = axis.options.position,
+                isXAxis = axis.direction === "x",
+                tickLength = axis.options.tickLength,
+                axisMargin = options.grid.axisMargin,
+                padding = options.grid.labelMargin,
+                innermost = true,
+                outermost = true,
+                first = true,
+                found = false;
+
+            // Determine the axis's position in its direction and on its side
+
+            $.each(isXAxis ? xaxes : yaxes, function(i, a) {
+                if (a && (a.show || a.reserveSpace)) {
+                    if (a === axis) {
+                        found = true;
+                    } else if (a.options.position === pos) {
+                        if (found) {
+                            outermost = false;
+                        } else {
+                            innermost = false;
+                        }
+                    }
+                    if (!found) {
+                        first = false;
+                    }
+                }
+            });
+
+            // The outermost axis on each side has no margin
+
+            if (outermost) {
+                axisMargin = 0;
+            }
+
+            // The ticks for the first axis in each direction stretch across
+
+            if (tickLength == null) {
+                tickLength = first ? "full" : 5;
+            }
+
+            if (!isNaN(+tickLength))
+                padding += +tickLength;
+
+            if (isXAxis) {
+                lh += padding;
+
+                if (pos == "bottom") {
+                    plotOffset.bottom += lh + axisMargin;
+                    axis.box = { top: surface.height - plotOffset.bottom, height: lh };
+                }
+                else {
+                    axis.box = { top: plotOffset.top + axisMargin, height: lh };
+                    plotOffset.top += lh + axisMargin;
+                }
+            }
+            else {
+                lw += padding;
+
+                if (pos == "left") {
+                    axis.box = { left: plotOffset.left + axisMargin, width: lw };
+                    plotOffset.left += lw + axisMargin;
+                }
+                else {
+                    plotOffset.right += lw + axisMargin;
+                    axis.box = { left: surface.width - plotOffset.right, width: lw };
+                }
+            }
+
+             // save for future reference
+            axis.position = pos;
+            axis.tickLength = tickLength;
+            axis.box.padding = padding;
+            axis.innermost = innermost;
+        }
+
+        function allocateAxisBoxSecondPhase(axis) {
+            // now that all axis boxes have been placed in one
+            // dimension, we can set the remaining dimension coordinates
+            if (axis.direction == "x") {
+                axis.box.left = plotOffset.left - axis.labelWidth / 2;
+                axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth;
+            }
+            else {
+                axis.box.top = plotOffset.top - axis.labelHeight / 2;
+                axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight;
+            }
+        }
+
+        function adjustLayoutForThingsStickingOut() {
+            // possibly adjust plot offset to ensure everything stays
+            // inside the canvas and isn't clipped off
+
+            var minMargin = options.grid.minBorderMargin,
+                axis, i;
+
+            // check stuff from the plot (FIXME: this should just read
+            // a value from the series, otherwise it's impossible to
+            // customize)
+            if (minMargin == null) {
+                minMargin = 0;
+                for (i = 0; i < series.length; ++i)
+                    minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2));
+            }
+
+            var margins = {
+                left: minMargin,
+                right: minMargin,
+                top: minMargin,
+                bottom: minMargin
+            };
+
+            // check axis labels, note we don't check the actual
+            // labels but instead use the overall width/height to not
+            // jump as much around with replots
+            $.each(allAxes(), function (_, axis) {
+                if (axis.reserveSpace && axis.ticks && axis.ticks.length) {
+                    if (axis.direction === "x") {
+                        margins.left = Math.max(margins.left, axis.labelWidth / 2);
+                        margins.right = Math.max(margins.right, axis.labelWidth / 2);
+                    } else {
+                        margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2);
+                        margins.top = Math.max(margins.top, axis.labelHeight / 2);
+                    }
+                }
+            });
+
+            plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left));
+            plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right));
+            plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top));
+            plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom));
+        }
+
+        function setupGrid() {
+            var i, axes = allAxes(), showGrid = options.grid.show;
+
+            // Initialize the plot's offset from the edge of the canvas
+
+            for (var a in plotOffset) {
+                var margin = options.grid.margin || 0;
+                plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0;
+            }
+
+            executeHooks(hooks.processOffset, [plotOffset]);
+
+            // If the grid is visible, add its border width to the offset
+
+            for (var a in plotOffset) {
+                if(typeof(options.grid.borderWidth) == "object") {
+                    plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0;
+                }
+                else {
+                    plotOffset[a] += showGrid ? options.grid.borderWidth : 0;
+                }
+            }
+
+            $.each(axes, function (_, axis) {
+                var axisOpts = axis.options;
+                axis.show = axisOpts.show == null ? axis.used : axisOpts.show;
+                axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace;
+                setRange(axis);
+            });
+
+            if (showGrid) {
+
+                var allocatedAxes = $.grep(axes, function (axis) {
+                    return axis.show || axis.reserveSpace;
+                });
+
+                $.each(allocatedAxes, function (_, axis) {
+                    // make the ticks
+                    setupTickGeneration(axis);
+                    setTicks(axis);
+                    snapRangeToTicks(axis, axis.ticks);
+                    // find labelWidth/Height for axis
+                    measureTickLabels(axis);
+                });
+
+                // with all dimensions calculated, we can compute the
+                // axis bounding boxes, start from the outside
+                // (reverse order)
+                for (i = allocatedAxes.length - 1; i >= 0; --i)
+                    allocateAxisBoxFirstPhase(allocatedAxes[i]);
+
+                // make sure we've got enough space for things that
+                // might stick out
+                adjustLayoutForThingsStickingOut();
+
+                $.each(allocatedAxes, function (_, axis) {
+                    allocateAxisBoxSecondPhase(axis);
+                });
+            }
+
+            plotWidth = surface.width - plotOffset.left - plotOffset.right;
+            plotHeight = surface.height - plotOffset.bottom - plotOffset.top;
+
+            // now we got the proper plot dimensions, we can compute the scaling
+            $.each(axes, function (_, axis) {
+                setTransformationHelpers(axis);
+            });
+
+            if (showGrid) {
+                drawAxisLabels();
+            }
+
+            insertLegend();
+        }
+
+        function setRange(axis) {
+            var opts = axis.options,
+                min = +(opts.min != null ? opts.min : axis.datamin),
+                max = +(opts.max != null ? opts.max : axis.datamax),
+                delta = max - min;
+
+            if (delta == 0.0) {
+                // degenerate case
+                var widen = max == 0 ? 1 : 0.01;
+
+                if (opts.min == null)
+                    min -= widen;
+                // always widen max if we couldn't widen min to ensure we
+                // don't fall into min == max which doesn't work
+                if (opts.max == null || opts.min != null)
+                    max += widen;
+            }
+            else {
+                // consider autoscaling
+                var margin = opts.autoscaleMargin;
+                if (margin != null) {
+                    if (opts.min == null) {
+                        min -= delta * margin;
+                        // make sure we don't go below zero if all values
+                        // are positive
+                        if (min < 0 && axis.datamin != null && axis.datamin >= 0)
+                            min = 0;
+                    }
+                    if (opts.max == null) {
+                        max += delta * margin;
+                        if (max > 0 && axis.datamax != null && axis.datamax <= 0)
+                            max = 0;
+                    }
+                }
+            }
+            axis.min = min;
+            axis.max = max;
+        }
+
+        function setupTickGeneration(axis) {
+            var opts = axis.options;
+
+            // estimate number of ticks
+            var noTicks;
+            if (typeof opts.ticks == "number" && opts.ticks > 0)
+                noTicks = opts.ticks;
+            else
+                // heuristic based on the model a*sqrt(x) fitted to
+                // some data points that seemed reasonable
+                noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height);
+
+            var delta = (axis.max - axis.min) / noTicks,
+                dec = -Math.floor(Math.log(delta) / Math.LN10),
+                maxDec = opts.tickDecimals;
+
+            if (maxDec != null && dec > maxDec) {
+                dec = maxDec;
+            }
+
+            var magn = Math.pow(10, -dec),
+                norm = delta / magn, // norm is between 1.0 and 10.0
+                size;
+
+            if (norm < 1.5) {
+                size = 1;
+            } else if (norm < 3) {
+                size = 2;
+                // special case for 2.5, requires an extra decimal
+                if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
+                    size = 2.5;
+                    ++dec;
+                }
+            } else if (norm < 7.5) {
+                size = 5;
+            } else {
+                size = 10;
+            }
+
+            size *= magn;
+
+            if (opts.minTickSize != null && size < opts.minTickSize) {
+                size = opts.minTickSize;
+            }
+
+            axis.delta = delta;
+            axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
+            axis.tickSize = opts.tickSize || size;
+
+            // Time mode was moved to a plug-in in 0.8, and since so many people use it
+            // we'll add an especially friendly reminder to make sure they included it.
+
+            if (opts.mode == "time" && !axis.tickGenerator) {
+                throw new Error("Time mode requires the flot.time plugin.");
+            }
+
+            // Flot supports base-10 axes; any other mode else is handled by a plug-in,
+            // like flot.time.js.
+
+            if (!axis.tickGenerator) {
+
+                axis.tickGenerator = function (axis) {
+
+                    var ticks = [],
+                        start = floorInBase(axis.min, axis.tickSize),
+                        i = 0,
+                        v = Number.NaN,
+                        prev;
+
+                    do {
+                        prev = v;
+                        v = start + i * axis.tickSize;
+                        ticks.push(v);
+                        ++i;
+                    } while (v < axis.max && v != prev);
+                    return ticks;
+                };
+
+				axis.tickFormatter = function (value, axis) {
+
+					var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1;
+					var formatted = "" + Math.round(value * factor) / factor;
+
+					// If tickDecimals was specified, ensure that we have exactly that
+					// much precision; otherwise default to the value's own precision.
+
+					if (axis.tickDecimals != null) {
+						var decimal = formatted.indexOf(".");
+						var precision = decimal == -1 ? 0 : formatted.length - decimal - 1;
+						if (precision < axis.tickDecimals) {
+							return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision);
+						}
+					}
+
+                    return formatted;
+                };
+            }
+
+            if ($.isFunction(opts.tickFormatter))
+                axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); };
+
+            if (opts.alignTicksWithAxis != null) {
+                var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];
+                if (otherAxis && otherAxis.used && otherAxis != axis) {
+                    // consider snapping min/max to outermost nice ticks
+                    var niceTicks = axis.tickGenerator(axis);
+                    if (niceTicks.length > 0) {
+                        if (opts.min == null)
+                            axis.min = Math.min(axis.min, niceTicks[0]);
+                        if (opts.max == null && niceTicks.length > 1)
+                            axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);
+                    }
+
+                    axis.tickGenerator = function (axis) {
+                        // copy ticks, scaled to this axis
+                        var ticks = [], v, i;
+                        for (i = 0; i < otherAxis.ticks.length; ++i) {
+                            v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min);
+                            v = axis.min + v * (axis.max - axis.min);
+                            ticks.push(v);
+                        }
+                        return ticks;
+                    };
+
+                    // we might need an extra decimal since forced
+                    // ticks don't necessarily fit naturally
+                    if (!axis.mode && opts.tickDecimals == null) {
+                        var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1),
+                            ts = axis.tickGenerator(axis);
+
+                        // only proceed if the tick interval rounded
+                        // with an extra decimal doesn't give us a
+                        // zero at end
+                        if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec))))
+                            axis.tickDecimals = extraDec;
+                    }
+                }
+            }
+        }
+
+        function setTicks(axis) {
+            var oticks = axis.options.ticks, ticks = [];
+            if (oticks == null || (typeof oticks == "number" && oticks > 0))
+                ticks = axis.tickGenerator(axis);
+            else if (oticks) {
+                if ($.isFunction(oticks))
+                    // generate the ticks
+                    ticks = oticks(axis);
+                else
+                    ticks = oticks;
+            }
+
+            // clean up/labelify the supplied ticks, copy them over
+            var i, v;
+            axis.ticks = [];
+            for (i = 0; i < ticks.length; ++i) {
+                var label = null;
+                var t = ticks[i];
+                if (typeof t == "object") {
+                    v = +t[0];
+                    if (t.length > 1)
+                        label = t[1];
+                }
+                else
+                    v = +t;
+                if (label == null)
+                    label = axis.tickFormatter(v, axis);
+                if (!isNaN(v))
+                    axis.ticks.push({ v: v, label: label });
+            }
+        }
+
+        function snapRangeToTicks(axis, ticks) {
+            if (axis.options.autoscaleMargin && ticks.length > 0) {
+                // snap to ticks
+                if (axis.options.min == null)
+                    axis.min = Math.min(axis.min, ticks[0].v);
+                if (axis.options.max == null && ticks.length > 1)
+                    axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);
+            }
+        }
+
+        function draw() {
+
+            surface.clear();
+
+            executeHooks(hooks.drawBackground, [ctx]);
+
+            var grid = options.grid;
+
+            // draw background, if any
+            if (grid.show && grid.backgroundColor)
+                drawBackground();
+
+            if (grid.show && !grid.aboveData) {
+                drawGrid();
+            }
+
+            for (var i = 0; i < series.length; ++i) {
+                executeHooks(hooks.drawSeries, [ctx, series[i]]);
+                drawSeries(series[i]);
+            }
+
+            executeHooks(hooks.draw, [ctx]);
+
+            if (grid.show && grid.aboveData) {
+                drawGrid();
+            }
+
+            surface.render();
+
+            // A draw implies that either the axes or data have changed, so we
+            // should probably update the overlay highlights as well.
+
+            triggerRedrawOverlay();
+        }
+
+        function extractRange(ranges, coord) {
+            var axis, from, to, key, axes = allAxes();
+
+            for (var i = 0; i < axes.length; ++i) {
+                axis = axes[i];
+                if (axis.direction == coord) {
+                    key = coord + axis.n + "axis";
+                    if (!ranges[key] && axis.n == 1)
+                        key = coord + "axis"; // support x1axis as xaxis
+                    if (ranges[key]) {
+                        from = ranges[key].from;
+                        to = ranges[key].to;
+                        break;
+                    }
+                }
+            }
+
+            // backwards-compat stuff - to be removed in future
+            if (!ranges[key]) {
+                axis = coord == "x" ? xaxes[0] : yaxes[0];
+                from = ranges[coord + "1"];
+                to = ranges[coord + "2"];
+            }
+
+            // auto-reverse as an added bonus
+            if (from != null && to != null && from > to) {
+                var tmp = from;
+                from = to;
+                to = tmp;
+            }
+
+            return { from: from, to: to, axis: axis };
+        }
+
+        function drawBackground() {
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+
+            ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)");
+            ctx.fillRect(0, 0, plotWidth, plotHeight);
+            ctx.restore();
+        }
+
+        function drawGrid() {
+            var i, axes, bw, bc;
+
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+
+            // draw markings
+            var markings = options.grid.markings;
+            if (markings) {
+                if ($.isFunction(markings)) {
+                    axes = plot.getAxes();
+                    // xmin etc. is backwards compatibility, to be
+                    // removed in the future
+                    axes.xmin = axes.xaxis.min;
+                    axes.xmax = axes.xaxis.max;
+                    axes.ymin = axes.yaxis.min;
+                    axes.ymax = axes.yaxis.max;
+
+                    markings = markings(axes);
+                }
+
+                for (i = 0; i < markings.length; ++i) {
+                    var m = markings[i],
+                        xrange = extractRange(m, "x"),
+                        yrange = extractRange(m, "y");
+
+                    // fill in missing
+                    if (xrange.from == null)
+                        xrange.from = xrange.axis.min;
+                    if (xrange.to == null)
+                        xrange.to = xrange.axis.max;
+                    if (yrange.from == null)
+                        yrange.from = yrange.axis.min;
+                    if (yrange.to == null)
+                        yrange.to = yrange.axis.max;
+
+                    // clip
+                    if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||
+                        yrange.to < yrange.axis.min || yrange.from > yrange.axis.max)
+                        continue;
+
+                    xrange.from = Math.max(xrange.from, xrange.axis.min);
+                    xrange.to = Math.min(xrange.to, xrange.axis.max);
+                    yrange.from = Math.max(yrange.from, yrange.axis.min);
+                    yrange.to = Math.min(yrange.to, yrange.axis.max);
+
+                    var xequal = xrange.from === xrange.to,
+                        yequal = yrange.from === yrange.to;
+
+                    if (xequal && yequal) {
+                        continue;
+                    }
+
+                    // then draw
+                    xrange.from = Math.floor(xrange.axis.p2c(xrange.from));
+                    xrange.to = Math.floor(xrange.axis.p2c(xrange.to));
+                    yrange.from = Math.floor(yrange.axis.p2c(yrange.from));
+                    yrange.to = Math.floor(yrange.axis.p2c(yrange.to));
+
+                    if (xequal || yequal) {
+                        var lineWidth = m.lineWidth || options.grid.markingsLineWidth,
+                            subPixel = lineWidth % 2 ? 0.5 : 0;
+                        ctx.beginPath();
+                        ctx.strokeStyle = m.color || options.grid.markingsColor;
+                        ctx.lineWidth = lineWidth;
+                        if (xequal) {
+                            ctx.moveTo(xrange.to + subPixel, yrange.from);
+                            ctx.lineTo(xrange.to + subPixel, yrange.to);
+                        } else {
+                            ctx.moveTo(xrange.from, yrange.to + subPixel);
+                            ctx.lineTo(xrange.to, yrange.to + subPixel);                            
+                        }
+                        ctx.stroke();
+                    } else {
+                        ctx.fillStyle = m.color || options.grid.markingsColor;
+                        ctx.fillRect(xrange.from, yrange.to,
+                                     xrange.to - xrange.from,
+                                     yrange.from - yrange.to);
+                    }
+                }
+            }
+
+            // draw the ticks
+            axes = allAxes();
+            bw = options.grid.borderWidth;
+
+            for (var j = 0; j < axes.length; ++j) {
+                var axis = axes[j], box = axis.box,
+                    t = axis.tickLength, x, y, xoff, yoff;
+                if (!axis.show || axis.ticks.length == 0)
+                    continue;
+
+                ctx.lineWidth = 1;
+
+                // find the edges
+                if (axis.direction == "x") {
+                    x = 0;
+                    if (t == "full")
+                        y = (axis.position == "top" ? 0 : plotHeight);
+                    else
+                        y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0);
+                }
+                else {
+                    y = 0;
+                    if (t == "full")
+                        x = (axis.position == "left" ? 0 : plotWidth);
+                    else
+                        x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0);
+                }
+
+                // draw tick bar
+                if (!axis.innermost) {
+                    ctx.strokeStyle = axis.options.color;
+                    ctx.beginPath();
+                    xoff = yoff = 0;
+                    if (axis.direction == "x")
+                        xoff = plotWidth + 1;
+                    else
+                        yoff = plotHeight + 1;
+
+                    if (ctx.lineWidth == 1) {
+                        if (axis.direction == "x") {
+                            y = Math.floor(y) + 0.5;
+                        } else {
+                            x = Math.floor(x) + 0.5;
+                        }
+                    }
+
+                    ctx.moveTo(x, y);
+                    ctx.lineTo(x + xoff, y + yoff);
+                    ctx.stroke();
+                }
+
+                // draw ticks
+
+                ctx.strokeStyle = axis.options.tickColor;
+
+                ctx.beginPath();
+                for (i = 0; i < axis.ticks.length; ++i) {
+                    var v = axis.ticks[i].v;
+
+                    xoff = yoff = 0;
+
+                    if (isNaN(v) || v < axis.min || v > axis.max
+                        // skip those lying on the axes if we got a border
+                        || (t == "full"
+                            && ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0)
+                            && (v == axis.min || v == axis.max)))
+                        continue;
+
+                    if (axis.direction == "x") {
+                        x = axis.p2c(v);
+                        yoff = t == "full" ? -plotHeight : t;
+
+                        if (axis.position == "top")
+                            yoff = -yoff;
+                    }
+                    else {
+                        y = axis.p2c(v);
+                        xoff = t == "full" ? -plotWidth : t;
+
+                        if (axis.position == "left")
+                            xoff = -xoff;
+                    }
+
+                    if (ctx.lineWidth == 1) {
+                        if (axis.direction == "x")
+                            x = Math.floor(x) + 0.5;
+                        else
+                            y = Math.floor(y) + 0.5;
+                    }
+
+
+                    if( (options.grid.TickLineStyle == 'dashed') && (yoff < -5 ) )
+                       { for (var yadd = y-2.5 ; yadd > y+yoff+5; yadd++ )
+                           {ctx.moveTo(x, yadd);
+                           ctx.lineTo(x + xoff, yadd - 5);
+                           yadd = yadd-10}   }
+                    else 
+                            ctx.moveTo(x, y);
+                            ctx.lineTo(x + xoff, y + yoff)
+                             }
+                    ctx.stroke();
+            }
+
+
+            // draw border
+            if (bw) {
+                // If either borderWidth or borderColor is an object, then draw the border
+                // line by line instead of as one rectangle
+                bc = options.grid.borderColor;
+                if(typeof bw == "object" || typeof bc == "object") {
+                    if (typeof bw !== "object") {
+                        bw = {top: bw, right: bw, bottom: bw, left: bw};
+                    }
+                    if (typeof bc !== "object") {
+                        bc = {top: bc, right: bc, bottom: bc, left: bc};
+                    }
+
+                    if (bw.top > 0) {
+                        ctx.strokeStyle = bc.top;
+                        ctx.lineWidth = bw.top;
+                        ctx.beginPath();
+                        ctx.moveTo(0 - bw.left, 0 - bw.top/2);
+                        ctx.lineTo(plotWidth, 0 - bw.top/2);
+                        ctx.stroke();
+                    }
+
+                    if (bw.right > 0) {
+                        ctx.strokeStyle = bc.right;
+                        ctx.lineWidth = bw.right;
+                        ctx.beginPath();
+                        ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top);
+                        ctx.lineTo(plotWidth + bw.right / 2, plotHeight);
+                        ctx.stroke();
+                    }
+
+                    if (bw.bottom > 0) {
+                        ctx.strokeStyle = bc.bottom;
+                        ctx.lineWidth = bw.bottom;
+                        ctx.beginPath();
+                        ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2);
+                        ctx.lineTo(0, plotHeight + bw.bottom / 2);
+                        ctx.stroke();
+                    }
+
+                    if (bw.left > 0) {
+                        ctx.strokeStyle = bc.left;
+                        ctx.lineWidth = bw.left;
+                        ctx.beginPath();
+                        ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom);
+                        ctx.lineTo(0- bw.left/2, 0);
+                        ctx.stroke();
+                    }
+                }
+                else {
+                    ctx.lineWidth = bw;
+                    ctx.strokeStyle = options.grid.borderColor;
+                    ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);
+                }
+            }
+
+            ctx.restore();
+        }
+
+        function drawAxisLabels() {
+
+            $.each(allAxes(), function (_, axis) {
+                var box = axis.box,
+                    legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
+                    layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
+                    font = axis.options.font || "flot-tick-label tickLabel",
+                    tick, x, y, halign, valign;
+
+                // Remove text before checking for axis.show and ticks.length;
+                // otherwise plugins, like flot-tickrotor, that draw their own
+                // tick labels will end up with both theirs and the defaults.
+
+                surface.removeText(layer);
+
+                if (!axis.show || axis.ticks.length == 0)
+                    return;
+
+                for (var i = 0; i < axis.ticks.length; ++i) {
+
+                    tick = axis.ticks[i];
+                    if (!tick.label || tick.v < axis.min || tick.v > axis.max)
+                        continue;
+
+                    if (axis.direction == "x") {
+                        halign = "center";
+                        x = plotOffset.left + axis.p2c(tick.v);
+                        if (axis.position == "bottom") {
+                            y = box.top + box.padding;
+                        } else {
+                            y = box.top + box.height - box.padding;
+                            valign = "bottom";
+                        }
+                    } else {
+                        valign = "middle";
+                        y = plotOffset.top + axis.p2c(tick.v);
+                        if (axis.position == "left") {
+                            x = box.left + box.width - box.padding;
+                            halign = "right";
+                        } else {
+                            x = box.left + box.padding;
+                        }
+                    }
+
+                    surface.addText(layer, x, y, tick.label, font, null, null, halign, valign);
+                }
+            });
+        }
+
+        function drawSeries(series) {
+            if (series.lines.show)
+                drawSeriesLines(series);
+            if (series.bars.show)
+                drawSeriesBars(series);
+            if (series.points.show)
+                drawSeriesPoints(series);
+        }
+
+        function drawSeriesLines(series) {
+            function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {
+                var points = datapoints.points,
+                    ps = datapoints.pointsize,
+                    prevx = null, prevy = null;
+
+                ctx.beginPath();
+                for (var i = ps; i < points.length; i += ps) {
+                    var x1 = points[i - ps], y1 = points[i - ps + 1],
+                        x2 = points[i], y2 = points[i + 1];
+
+                    if (x1 == null || x2 == null)
+                        continue;
+
+                    // clip with ymin
+                    if (y1 <= y2 && y1 < axisy.min) {
+                        if (y2 < axisy.min)
+                            continue;   // line segment is outside
+                        // compute new intersection point
+                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y1 = axisy.min;
+                    }
+                    else if (y2 <= y1 && y2 < axisy.min) {
+                        if (y1 < axisy.min)
+                            continue;
+                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y2 = axisy.min;
+                    }
+
+                    // clip with ymax
+                    if (y1 >= y2 && y1 > axisy.max) {
+                        if (y2 > axisy.max)
+                            continue;
+                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y1 = axisy.max;
+                    }
+                    else if (y2 >= y1 && y2 > axisy.max) {
+                        if (y1 > axisy.max)
+                            continue;
+                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y2 = axisy.max;
+                    }
+
+                    // clip with xmin
+                    if (x1 <= x2 && x1 < axisx.min) {
+                        if (x2 < axisx.min)
+                            continue;
+                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x1 = axisx.min;
+                    }
+                    else if (x2 <= x1 && x2 < axisx.min) {
+                        if (x1 < axisx.min)
+                            continue;
+                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x2 = axisx.min;
+                    }
+
+                    // clip with xmax
+                    if (x1 >= x2 && x1 > axisx.max) {
+                        if (x2 > axisx.max)
+                            continue;
+                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x1 = axisx.max;
+                    }
+                    else if (x2 >= x1 && x2 > axisx.max) {
+                        if (x1 > axisx.max)
+                            continue;
+                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x2 = axisx.max;
+                    }
+
+                    if (x1 != prevx || y1 != prevy)
+                        ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
+
+                    prevx = x2;
+                    prevy = y2;
+                    ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);
+                }
+                ctx.stroke();
+            }
+
+            function plotLineArea(datapoints, axisx, axisy) {
+                var points = datapoints.points,
+                    ps = datapoints.pointsize,
+                    bottom = Math.min(Math.max(0, axisy.min), axisy.max),
+                    i = 0, top, areaOpen = false,
+                    ypos = 1, segmentStart = 0, segmentEnd = 0;
+
+                // we process each segment in two turns, first forward
+                // direction to sketch out top, then once we hit the
+                // end we go backwards to sketch the bottom
+                while (true) {
+                    if (ps > 0 && i > points.length + ps)
+                        break;
+
+                    i += ps; // ps is negative if going backwards
+
+                    var x1 = points[i - ps],
+                        y1 = points[i - ps + ypos],
+                        x2 = points[i], y2 = points[i + ypos];
+
+                    if (areaOpen) {
+                        if (ps > 0 && x1 != null && x2 == null) {
+                            // at turning point
+                            segmentEnd = i;
+                            ps = -ps;
+                            ypos = 2;
+                            continue;
+                        }
+
+                        if (ps < 0 && i == segmentStart + ps) {
+                            // done with the reverse sweep
+                            ctx.fill();
+                            areaOpen = false;
+                            ps = -ps;
+                            ypos = 1;
+                            i = segmentStart = segmentEnd + ps;
+                            continue;
+                        }
+                    }
+
+                    if (x1 == null || x2 == null)
+                        continue;
+
+                    // clip x values
+
+                    // clip with xmin
+                    if (x1 <= x2 && x1 < axisx.min) {
+                        if (x2 < axisx.min)
+                            continue;
+                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x1 = axisx.min;
+                    }
+                    else if (x2 <= x1 && x2 < axisx.min) {
+                        if (x1 < axisx.min)
+                            continue;
+                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x2 = axisx.min;
+                    }
+
+                    // clip with xmax
+                    if (x1 >= x2 && x1 > axisx.max) {
+                        if (x2 > axisx.max)
+                            continue;
+                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x1 = axisx.max;
+                    }
+                    else if (x2 >= x1 && x2 > axisx.max) {
+                        if (x1 > axisx.max)
+                            continue;
+                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x2 = axisx.max;
+                    }
+
+                    if (!areaOpen) {
+                        // open area
+                        ctx.beginPath();
+                        ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
+                        areaOpen = true;
+                    }
+
+                    // now first check the case where both is outside
+                    if (y1 >= axisy.max && y2 >= axisy.max) {
+                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
+                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
+                        continue;
+                    }
+                    else if (y1 <= axisy.min && y2 <= axisy.min) {
+                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
+                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
+                        continue;
+                    }
+
+                    // else it's a bit more complicated, there might
+                    // be a flat maxed out rectangle first, then a
+                    // triangular cutout or reverse; to find these
+                    // keep track of the current x values
+                    var x1old = x1, x2old = x2;
+
+                    // clip the y values, without shortcutting, we
+                    // go through all cases in turn
+
+                    // clip with ymin
+                    if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
+                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y1 = axisy.min;
+                    }
+                    else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {
+                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y2 = axisy.min;
+                    }
+
+                    // clip with ymax
+                    if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {
+                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y1 = axisy.max;
+                    }
+                    else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {
+                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y2 = axisy.max;
+                    }
+
+                    // if the x value was changed we got a rectangle
+                    // to fill
+                    if (x1 != x1old) {
+                        ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
+                        // it goes to (x1, y1), but we fill that below
+                    }
+
+                    // fill triangular section, this sometimes result
+                    // in redundant points if (x1, y1) hasn't changed
+                    // from previous line to, but we just ignore that
+                    ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
+                    ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
+
+                    // fill the other rectangle if it's there
+                    if (x2 != x2old) {
+                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
+                        ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));
+                    }
+                }
+            }
+
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+            ctx.lineJoin = "round";
+
+            var lw = series.lines.lineWidth,
+                sw = series.shadowSize;
+            // FIXME: consider another form of shadow when filling is turned on
+            if (lw > 0 && sw > 0) {
+                // draw shadow as a thick and thin line with transparency
+                ctx.lineWidth = sw;
+                ctx.strokeStyle = "rgba(0,0,0,0.1)";
+                // position shadow at angle from the mid of line
+                var angle = Math.PI/18;
+                plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis);
+                ctx.lineWidth = sw/2;
+                plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis);
+            }
+
+            ctx.lineWidth = lw;
+            ctx.strokeStyle = series.color;
+            var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight);
+            if (fillStyle) {
+                ctx.fillStyle = fillStyle;
+                plotLineArea(series.datapoints, series.xaxis, series.yaxis);
+            }
+
+            if (lw > 0)
+                plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis);
+            ctx.restore();
+        }
+
+        function drawSeriesPoints(series) {
+            function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) {
+                var points = datapoints.points, ps = datapoints.pointsize;
+
+                for (var i = 0; i < points.length; i += ps) {
+                    var x = points[i], y = points[i + 1];
+                    if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
+                        continue;
+
+                    ctx.beginPath();
+                    x = axisx.p2c(x);
+                    y = axisy.p2c(y) + offset;
+                    if (symbol == "circle")
+                        ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);
+                    else
+                        symbol(ctx, x, y, radius, shadow);
+                    ctx.closePath();
+
+                    if (fillStyle) {
+                        ctx.fillStyle = fillStyle;
+                        ctx.fill();
+                    }
+                    ctx.stroke();
+                }
+            }
+
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+
+            var lw = series.points.lineWidth,
+                sw = series.shadowSize,
+                radius = series.points.radius,
+                symbol = series.points.symbol;
+
+            // If the user sets the line width to 0, we change it to a very 
+            // small value. A line width of 0 seems to force the default of 1.
+            // Doing the conditional here allows the shadow setting to still be 
+            // optional even with a lineWidth of 0.
+
+            if( lw == 0 )
+                lw = 0.0001;
+
+            if (lw > 0 && sw > 0) {
+                // draw shadow in two steps
+                var w = sw / 2;
+                ctx.lineWidth = w;
+                ctx.strokeStyle = "rgba(0,0,0,0.1)";
+                plotPoints(series.datapoints, radius, null, w + w/2, true,
+                           series.xaxis, series.yaxis, symbol);
+
+                ctx.strokeStyle = "rgba(0,0,0,0.2)";
+                plotPoints(series.datapoints, radius, null, w/2, true,
+                           series.xaxis, series.yaxis, symbol);
+            }
+
+            ctx.lineWidth = lw;
+            ctx.strokeStyle = series.color;
+            plotPoints(series.datapoints, radius,
+                       getFillStyle(series.points, series.color), 0, false,
+                       series.xaxis, series.yaxis, symbol);
+            ctx.restore();
+        }
+
+        function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
+            var left, right, bottom, top,
+                drawLeft, drawRight, drawTop, drawBottom,
+                tmp;
+
+            // in horizontal mode, we start the bar from the left
+            // instead of from the bottom so it appears to be
+            // horizontal rather than vertical
+            if (horizontal) {
+                drawBottom = drawRight = drawTop = true;
+                drawLeft = false;
+                left = b;
+                right = x;
+                top = y + barLeft;
+                bottom = y + barRight;
+
+                // account for negative bars
+                if (right < left) {
+                    tmp = right;
+                    right = left;
+                    left = tmp;
+                    drawLeft = true;
+                    drawRight = false;
+                }
+            }
+            else {
+                drawLeft = drawRight = drawTop = true;
+                drawBottom = false;
+                left = x + barLeft;
+                right = x + barRight;
+                bottom = b;
+                top = y;
+
+                // account for negative bars
+                if (top < bottom) {
+                    tmp = top;
+                    top = bottom;
+                    bottom = tmp;
+                    drawBottom = true;
+                    drawTop = false;
+                }
+            }
+
+            // clip
+            if (right < axisx.min || left > axisx.max ||
+                top < axisy.min || bottom > axisy.max)
+                return;
+
+            if (left < axisx.min) {
+                left = axisx.min;
+                drawLeft = false;
+            }
+
+            if (right > axisx.max) {
+                right = axisx.max;
+                drawRight = false;
+            }
+
+            if (bottom < axisy.min) {
+                bottom = axisy.min;
+                drawBottom = false;
+            }
+
+            if (top > axisy.max) {
+                top = axisy.max;
+                drawTop = false;
+            }
+
+            left = axisx.p2c(left);
+            bottom = axisy.p2c(bottom);
+            right = axisx.p2c(right);
+            top = axisy.p2c(top);
+
+            // fill the bar
+            if (fillStyleCallback) {
+                c.fillStyle = fillStyleCallback(bottom, top);
+                c.fillRect(left, top, right - left, bottom - top)
+            }
+
+            // draw outline
+            if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {
+                c.beginPath();
+
+                // FIXME: inline moveTo is buggy with excanvas
+                c.moveTo(left, bottom);
+                if (drawLeft)
+                    c.lineTo(left, top);
+                else
+                    c.moveTo(left, top);
+                if (drawTop)
+                    c.lineTo(right, top);
+                else
+                    c.moveTo(right, top);
+                if (drawRight)
+                    c.lineTo(right, bottom);
+                else
+                    c.moveTo(right, bottom);
+                if (drawBottom)
+                    c.lineTo(left, bottom);
+                else
+                    c.moveTo(left, bottom);
+                c.stroke();
+            }
+        }
+
+        function drawSeriesBars(series) {
+            function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) {
+                var points = datapoints.points, ps = datapoints.pointsize;
+
+                for (var i = 0; i < points.length; i += ps) {
+                    if (points[i] == null)
+                        continue;
+                    drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
+                }
+            }
+
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+
+            // FIXME: figure out a way to add shadows (for instance along the right edge)
+            ctx.lineWidth = series.bars.lineWidth;
+            ctx.strokeStyle = series.color;
+
+            var barLeft;
+
+            switch (series.bars.align) {
+                case "left":
+                    barLeft = 0;
+                    break;
+                case "right":
+                    barLeft = -series.bars.barWidth;
+                    break;
+                default:
+                    barLeft = -series.bars.barWidth / 2;
+            }
+
+            var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;
+            plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis);
+            ctx.restore();
+        }
+
+        function getFillStyle(filloptions, seriesColor, bottom, top) {
+            var fill = filloptions.fill;
+            if (!fill)
+                return null;
+
+            if (filloptions.fillColor)
+                return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);
+
+            var c = $.color.parse(seriesColor);
+            c.a = typeof fill == "number" ? fill : 0.4;
+            c.normalize();
+            return c.toString();
+        }
+
+        function insertLegend() {
+
+            if (options.legend.container != null) {
+                $(options.legend.container).html("");
+            } else {
+                placeholder.find(".legend").remove();
+            }
+
+            if (!options.legend.show) {
+                return;
+            }
+
+            var fragments = [], entries = [], rowStarted = false,
+                lf = options.legend.labelFormatter, s, label;
+
+            // Build a list of legend entries, with each having a label and a color
+
+            for (var i = 0; i < series.length; ++i) {
+                s = series[i];
+                if (s.label) {
+                    label = lf ? lf(s.label, s) : s.label;
+                    if (label) {
+                        entries.push({
+                            label: label,
+                            color: s.color
+                        });
+                    }
+                }
+            }
+
+            // Sort the legend using either the default or a custom comparator
+
+            if (options.legend.sorted) {
+                if ($.isFunction(options.legend.sorted)) {
+                    entries.sort(options.legend.sorted);
+                } else if (options.legend.sorted == "reverse") {
+                	entries.reverse();
+                } else {
+                    var ascending = options.legend.sorted != "descending";
+                    entries.sort(function(a, b) {
+                        return a.label == b.label ? 0 : (
+                            (a.label < b.label) != ascending ? 1 : -1   // Logical XOR
+                        );
+                    });
+                }
+            }
+
+            // Generate markup for the list of entries, in their final order
+
+            for (var i = 0; i < entries.length; ++i) {
+
+                var entry = entries[i];
+
+                if (i % options.legend.noColumns == 0) {
+                    if (rowStarted)
+                        fragments.push('</tr>');
+                    fragments.push('<tr>');
+                    rowStarted = true;
+                }
+
+                fragments.push(
+                    '<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' + entry.color + ';overflow:hidden"></div></div></td>' +
+                    '<td class="legendLabel">' + entry.label + '</td>'
+                );
+            }
+
+            if (rowStarted)
+                fragments.push('</tr>');
+
+            if (fragments.length == 0)
+                return;
+
+            var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';
+            if (options.legend.container != null)
+                $(options.legend.container).html(table);
+            else {
+                var pos = "",
+                    p = options.legend.position,
+                    m = options.legend.margin;
+                if (m[0] == null)
+                    m = [m, m];
+                if (p.charAt(0) == "n")
+                    pos += 'top:' + (m[1] + plotOffset.top) + 'px;';
+                else if (p.charAt(0) == "s")
+                    pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';
+                if (p.charAt(1) == "e")
+                    pos += 'right:' + (m[0] + plotOffset.right) + 'px;';
+                else if (p.charAt(1) == "w")
+                    pos += 'left:' + (m[0] + plotOffset.left) + 'px;';
+                var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(placeholder);
+                if (options.legend.backgroundOpacity != 0.0) {
+                    // put in the transparent background
+                    // separately to avoid blended labels and
+                    // label boxes
+                    var c = options.legend.backgroundColor;
+                    if (c == null) {
+                        c = options.grid.backgroundColor;
+                        if (c && typeof c == "string")
+                            c = $.color.parse(c);
+                        else
+                            c = $.color.extract(legend, 'background-color');
+                        c.a = 1;
+                        c = c.toString();
+                    }
+                    var div = legend.children();
+                    $('<div style="position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity);
+                }
+            }
+        }
+
+
+        // interactive features
+
+        var highlights = [],
+            redrawTimeout = null;
+
+        // returns the data item the mouse is over, or null if none is found
+        function findNearbyItem(mouseX, mouseY, seriesFilter) {
+            var maxDistance = options.grid.mouseActiveRadius,
+                smallestDistance = maxDistance * maxDistance + 1,
+                item = null, foundPoint = false, i, j, ps;
+
+            for (i = series.length - 1; i >= 0; --i) {
+                if (!seriesFilter(series[i]))
+                    continue;
+
+                var s = series[i],
+                    axisx = s.xaxis,
+                    axisy = s.yaxis,
+                    points = s.datapoints.points,
+                    mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster
+                    my = axisy.c2p(mouseY),
+                    maxx = maxDistance / axisx.scale,
+                    maxy = maxDistance / axisy.scale;
+
+                ps = s.datapoints.pointsize;
+                // with inverse transforms, we can't use the maxx/maxy
+                // optimization, sadly
+                if (axisx.options.inverseTransform)
+                    maxx = Number.MAX_VALUE;
+                if (axisy.options.inverseTransform)
+                    maxy = Number.MAX_VALUE;
+
+                if (s.lines.show || s.points.show) {
+                    for (j = 0; j < points.length; j += ps) {
+                        var x = points[j], y = points[j + 1];
+                        if (x == null)
+                            continue;
+
+                        // For points and lines, the cursor must be within a
+                        // certain distance to the data point
+                        if (x - mx > maxx || x - mx < -maxx ||
+                            y - my > maxy || y - my < -maxy)
+                            continue;
+
+                        // We have to calculate distances in pixels, not in
+                        // data units, because the scales of the axes may be different
+                        var dx = Math.abs(axisx.p2c(x) - mouseX),
+                            dy = Math.abs(axisy.p2c(y) - mouseY),
+                            dist = dx * dx + dy * dy; // we save the sqrt
+
+                        // use <= to ensure last point takes precedence
+                        // (last generally means on top of)
+                        if (dist < smallestDistance) {
+                            smallestDistance = dist;
+                            item = [i, j / ps];
+                        }
+                    }
+                }
+
+                if (s.bars.show && !item) { // no other point can be nearby
+
+                    var barLeft, barRight;
+
+                    switch (s.bars.align) {
+                        case "left":
+                            barLeft = 0;
+                            break;
+                        case "right":
+                            barLeft = -s.bars.barWidth;
+                            break;
+                        default:
+                            barLeft = -s.bars.barWidth / 2;
+                    }
+
+                    barRight = barLeft + s.bars.barWidth;
+
+                    for (j = 0; j < points.length; j += ps) {
+                        var x = points[j], y = points[j + 1], b = points[j + 2];
+                        if (x == null)
+                            continue;
+
+                        // for a bar graph, the cursor must be inside the bar
+                        if (series[i].bars.horizontal ?
+                            (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
+                             my >= y + barLeft && my <= y + barRight) :
+                            (mx >= x + barLeft && mx <= x + barRight &&
+                             my >= Math.min(b, y) && my <= Math.max(b, y)))
+                                item = [i, j / ps];
+                    }
+                }
+            }
+
+            if (item) {
+                i = item[0];
+                j = item[1];
+                ps = series[i].datapoints.pointsize;
+
+                return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),
+                         dataIndex: j,
+                         series: series[i],
+                         seriesIndex: i };
+            }
+
+            return null;
+        }
+
+        function onMouseMove(e) {
+            if (options.grid.hoverable)
+                triggerClickHoverEvent("plothover", e,
+                                       function (s) { return s["hoverable"] != false; });
+        }
+
+        function onMouseLeave(e) {
+            if (options.grid.hoverable)
+                triggerClickHoverEvent("plothover", e,
+                                       function (s) { return false; });
+        }
+
+        function onClick(e) {
+            triggerClickHoverEvent("plotclick", e,
+                                   function (s) { return s["clickable"] != false; });
+        }
+
+        // trigger click or hover event (they send the same parameters
+        // so we share their code)
+        function triggerClickHoverEvent(eventname, event, seriesFilter) {
+            var offset = eventHolder.offset(),
+                canvasX = event.pageX - offset.left - plotOffset.left,
+                canvasY = event.pageY - offset.top - plotOffset.top,
+            pos = canvasToAxisCoords({ left: canvasX, top: canvasY });
+
+            pos.pageX = event.pageX;
+            pos.pageY = event.pageY;
+
+            var item = findNearbyItem(canvasX, canvasY, seriesFilter);
+
+            if (item) {
+                // fill in mouse pos for any listeners out there
+                item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10);
+                item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10);
+            }
+
+            if (options.grid.autoHighlight) {
+                // clear auto-highlights
+                for (var i = 0; i < highlights.length; ++i) {
+                    var h = highlights[i];
+                    if (h.auto == eventname &&
+                        !(item && h.series == item.series &&
+                          h.point[0] == item.datapoint[0] &&
+                          h.point[1] == item.datapoint[1]))
+                        unhighlight(h.series, h.point);
+                }
+
+                if (item)
+                    highlight(item.series, item.datapoint, eventname);
+            }
+
+            placeholder.trigger(eventname, [ pos, item ]);
+        }
+
+        function triggerRedrawOverlay() {
+            var t = options.interaction.redrawOverlayInterval;
+            if (t == -1) {      // skip event queue
+                drawOverlay();
+                return;
+            }
+
+            if (!redrawTimeout)
+                redrawTimeout = setTimeout(drawOverlay, t);
+        }
+
+        function drawOverlay() {
+            redrawTimeout = null;
+
+            // draw highlights
+            octx.save();
+            overlay.clear();
+            octx.translate(plotOffset.left, plotOffset.top);
+
+            var i, hi;
+            for (i = 0; i < highlights.length; ++i) {
+                hi = highlights[i];
+
+                if (hi.series.bars.show)
+                    drawBarHighlight(hi.series, hi.point);
+                else
+                    drawPointHighlight(hi.series, hi.point);
+            }
+            octx.restore();
+
+            executeHooks(hooks.drawOverlay, [octx]);
+        }
+
+        function highlight(s, point, auto) {
+            if (typeof s == "number")
+                s = series[s];
+
+            if (typeof point == "number") {
+                var ps = s.datapoints.pointsize;
+                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
+            }
+
+            var i = indexOfHighlight(s, point);
+            if (i == -1) {
+                highlights.push({ series: s, point: point, auto: auto });
+
+                triggerRedrawOverlay();
+            }
+            else if (!auto)
+                highlights[i].auto = false;
+        }
+
+        function unhighlight(s, point) {
+            if (s == null && point == null) {
+                highlights = [];
+                triggerRedrawOverlay();
+                return;
+            }
+
+            if (typeof s == "number")
+                s = series[s];
+
+            if (typeof point == "number") {
+                var ps = s.datapoints.pointsize;
+                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
+            }
+
+            var i = indexOfHighlight(s, point);
+            if (i != -1) {
+                highlights.splice(i, 1);
+
+                triggerRedrawOverlay();
+            }
+        }
+
+        function indexOfHighlight(s, p) {
+            for (var i = 0; i < highlights.length; ++i) {
+                var h = highlights[i];
+                if (h.series == s && h.point[0] == p[0]
+                    && h.point[1] == p[1])
+                    return i;
+            }
+            return -1;
+        }
+
+        function drawPointHighlight(series, point) {
+            var x = point[0], y = point[1],
+                axisx = series.xaxis, axisy = series.yaxis,
+                highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();
+
+            if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
+                return;
+
+            var pointRadius = series.points.radius + series.points.lineWidth / 2;
+            octx.lineWidth = pointRadius;
+            octx.strokeStyle = highlightColor;
+            var radius = 1.5 * pointRadius;
+            x = axisx.p2c(x);
+            y = axisy.p2c(y);
+
+            octx.beginPath();
+            if (series.points.symbol == "circle")
+                octx.arc(x, y, radius, 0, 2 * Math.PI, false);
+            else
+                series.points.symbol(octx, x, y, radius, false);
+            octx.closePath();
+            octx.stroke();
+        }
+
+        function drawBarHighlight(series, point) {
+            var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
+                fillStyle = highlightColor,
+                barLeft;
+
+            switch (series.bars.align) {
+                case "left":
+                    barLeft = 0;
+                    break;
+                case "right":
+                    barLeft = -series.bars.barWidth;
+                    break;
+                default:
+                    barLeft = -series.bars.barWidth / 2;
+            }
+
+            octx.lineWidth = series.bars.lineWidth;
+            octx.strokeStyle = highlightColor;
+
+            drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,
+                    function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
+        }
+
+        function getColorOrGradient(spec, bottom, top, defaultColor) {
+            if (typeof spec == "string")
+                return spec;
+            else {
+                // assume this is a gradient spec; IE currently only
+                // supports a simple vertical gradient properly, so that's
+                // what we support too
+                var gradient = ctx.createLinearGradient(0, top, 0, bottom);
+
+                for (var i = 0, l = spec.colors.length; i < l; ++i) {
+                    var c = spec.colors[i];
+                    if (typeof c != "string") {
+                        var co = $.color.parse(defaultColor);
+                        if (c.brightness != null)
+                            co = co.scale('rgb', c.brightness);
+                        if (c.opacity != null)
+                            co.a *= c.opacity;
+                        c = co.toString();
+                    }
+                    gradient.addColorStop(i / (l - 1), c);
+                }
+
+                return gradient;
+            }
+        }
+    }
+
+    // Add the plot function to the top level of the jQuery object
+
+    $.plot = function(placeholder, data, options) {
+        //var t0 = new Date();
+        var plot = new Plot($(placeholder), data, options, $.plot.plugins);
+        //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime()));
+        return plot;
+    };
+
+    $.plot.version = "0.8.3";
+
+    $.plot.plugins = [];
+
+    // Also add the plot function as a chainable property
+
+    $.fn.plot = function(data, options) {
+        return this.each(function() {
+            $.plot(this, data, options);
+        });
+    };
+
+    // round to nearby lower multiple of base
+    function floorInBase(n, base) {
+        return base * Math.floor(n / base);
+    }
+
+})(jQuery);
diff --git a/js/jquery.flot.navigate.js b/js/jquery.flot.navigate.js
new file mode 100644
index 0000000000000000000000000000000000000000..f2b97603c321bcb9dc1ebee45e61a7c19cdd46f3
--- /dev/null
+++ b/js/jquery.flot.navigate.js
@@ -0,0 +1,336 @@
+/*
+Flot plugin for adding panning and zooming capabilities to a plot.
+
+The default behaviour is double click and scrollwheel up/down to zoom
+in, drag to pan. The plugin defines plot.zoom({ center }),
+plot.zoomOut() and plot.pan(offset) so you easily can add custom
+controls. It also fires a "plotpan" and "plotzoom" event when
+something happens, useful for synchronizing plots.
+
+Options:
+
+  zoom: {
+    interactive: false
+    trigger: "dblclick" // or "click" for single click
+    amount: 1.5         // 2 = 200% (zoom in), 0.5 = 50% (zoom out)
+  }
+  
+  pan: {
+    interactive: false
+    cursor: "move"      // CSS mouse cursor value used when dragging, e.g. "pointer"
+    frameRate: 20
+  }
+
+  xaxis, yaxis, x2axis, y2axis: {
+    zoomRange: null  // or [number, number] (min range, max range) or false
+    panRange: null   // or [number, number] (min, max) or false
+  }
+  
+"interactive" enables the built-in drag/click behaviour. If you enable
+interactive for pan, then you'll have a basic plot that supports
+moving around; the same for zoom.
+
+"amount" specifies the default amount to zoom in (so 1.5 = 150%)
+relative to the current viewport.
+
+"cursor" is a standard CSS mouse cursor string used for visual
+feedback to the user when dragging.
+
+"frameRate" specifies the maximum number of times per second the plot
+will update itself while the user is panning around on it (set to null
+to disable intermediate pans, the plot will then not update until the
+mouse button is released).
+
+"zoomRange" is the interval in which zooming can happen, e.g. with
+zoomRange: [1, 100] the zoom will never scale the axis so that the
+difference between min and max is smaller than 1 or larger than 100.
+You can set either end to null to ignore, e.g. [1, null]. If you set
+zoomRange to false, zooming on that axis will be disabled.
+
+"panRange" confines the panning to stay within a range, e.g. with
+panRange: [-10, 20] panning stops at -10 in one end and at 20 in the
+other. Either can be null, e.g. [-10, null]. If you set
+panRange to false, panning on that axis will be disabled.
+
+Example API usage:
+
+  plot = $.plot(...);
+  
+  // zoom default amount in on the pixel (10, 20) 
+  plot.zoom({ center: { left: 10, top: 20 } });
+
+  // zoom out again
+  plot.zoomOut({ center: { left: 10, top: 20 } });
+
+  // zoom 200% in on the pixel (10, 20) 
+  plot.zoom({ amount: 2, center: { left: 10, top: 20 } });
+  
+  // pan 100 pixels to the left and 20 down
+  plot.pan({ left: -100, top: 20 })
+
+Here, "center" specifies where the center of the zooming should
+happen. Note that this is defined in pixel space, not the space of the
+data points (you can use the p2c helpers on the axes in Flot to help
+you convert between these).
+
+"amount" is the amount to zoom the viewport relative to the current
+range, so 1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is
+70% (zoom out). You can set the default in the options.
+  
+*/
+
+
+// First two dependencies, jquery.event.drag.js and
+// jquery.mousewheel.js, we put them inline here to save people the
+// effort of downloading them.
+
+/*
+jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)  
+Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt
+*/
+(function(E){E.fn.drag=function(L,K,J){if(K){this.bind("dragstart",L)}if(J){this.bind("dragend",J)}return !L?this.trigger("drag"):this.bind("drag",K?K:L)};var A=E.event,B=A.special,F=B.drag={not:":input",distance:0,which:1,dragging:false,setup:function(J){J=E.extend({distance:F.distance,which:F.which,not:F.not},J||{});J.distance=I(J.distance);A.add(this,"mousedown",H,J);if(this.attachEvent){this.attachEvent("ondragstart",D)}},teardown:function(){A.remove(this,"mousedown",H);if(this===F.dragging){F.dragging=F.proxy=false}G(this,true);if(this.detachEvent){this.detachEvent("ondragstart",D)}}};B.dragstart=B.dragend={setup:function(){},teardown:function(){}};function H(L){var K=this,J,M=L.data||{};if(M.elem){K=L.dragTarget=M.elem;L.dragProxy=F.proxy||K;L.cursorOffsetX=M.pageX-M.left;L.cursorOffsetY=M.pageY-M.top;L.offsetX=L.pageX-L.cursorOffsetX;L.offsetY=L.pageY-L.cursorOffsetY}else{if(F.dragging||(M.which>0&&L.which!=M.which)||E(L.target).is(M.not)){return }}switch(L.type){case"mousedown":E.extend(M,E(K).offset(),{elem:K,target:L.target,pageX:L.pageX,pageY:L.pageY});A.add(document,"mousemove mouseup",H,M);G(K,false);F.dragging=null;return false;case !F.dragging&&"mousemove":if(I(L.pageX-M.pageX)+I(L.pageY-M.pageY)<M.distance){break}L.target=M.target;J=C(L,"dragstart",K);if(J!==false){F.dragging=K;F.proxy=L.dragProxy=E(J||K)[0]}case"mousemove":if(F.dragging){J=C(L,"drag",K);if(B.drop){B.drop.allowed=(J!==false);B.drop.handler(L)}if(J!==false){break}L.type="mouseup"}case"mouseup":A.remove(document,"mousemove mouseup",H);if(F.dragging){if(B.drop){B.drop.handler(L)}C(L,"dragend",K)}G(K,true);F.dragging=F.proxy=M.elem=false;break}return true}function C(M,K,L){M.type=K;var J=E.event.handle.call(L,M);return J===false?false:J||M.result}function I(J){return Math.pow(J,2)}function D(){return(F.dragging===false)}function G(K,J){if(!K){return }K.unselectable=J?"off":"on";K.onselectstart=function(){return J};if(K.style){K.style.MozUserSelect=J?"":"none"}}})(jQuery);
+
+
+/* jquery.mousewheel.min.js
+ * Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ *
+ * Version: 3.0.2
+ * 
+ * Requires: 1.2.2+
+ */
+(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery);
+
+
+
+
+(function ($) {
+    var options = {
+        xaxis: {
+            zoomRange: null, // or [number, number] (min range, max range)
+            panRange: null // or [number, number] (min, max)
+        },
+        zoom: {
+            interactive: false,
+            trigger: "dblclick", // or "click" for single click
+            amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out)
+        },
+        pan: {
+            interactive: false,
+            cursor: "move",
+            frameRate: 20
+        }
+    };
+
+    function init(plot) {
+        function onZoomClick(e, zoomOut) {
+            var c = plot.offset();
+            c.left = e.pageX - c.left;
+            c.top = e.pageY - c.top;
+            if (zoomOut)
+                plot.zoomOut({ center: c });
+            else
+                plot.zoom({ center: c });
+        }
+
+        function onMouseWheel(e, delta) {
+            onZoomClick(e, delta < 0);
+            return false;
+        }
+        
+        var prevCursor = 'default', prevPageX = 0, prevPageY = 0,
+            panTimeout = null;
+
+        function onDragStart(e) {
+            if (e.which != 1)  // only accept left-click
+                return false;
+            var c = plot.getPlaceholder().css('cursor');
+            if (c)
+                prevCursor = c;
+            plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor);
+            prevPageX = e.pageX;
+            prevPageY = e.pageY;
+        }
+        
+        function onDrag(e) {
+            var frameRate = plot.getOptions().pan.frameRate;
+            if (panTimeout || !frameRate)
+                return;
+
+            panTimeout = setTimeout(function () {
+                plot.pan({ left: prevPageX - e.pageX,
+                           top: prevPageY - e.pageY });
+                prevPageX = e.pageX;
+                prevPageY = e.pageY;
+                                                    
+                panTimeout = null;
+            }, 1 / frameRate * 1000);
+        }
+
+        function onDragEnd(e) {
+            if (panTimeout) {
+                clearTimeout(panTimeout);
+                panTimeout = null;
+            }
+                    
+            plot.getPlaceholder().css('cursor', prevCursor);
+            plot.pan({ left: prevPageX - e.pageX,
+                       top: prevPageY - e.pageY });
+        }
+        
+        function bindEvents(plot, eventHolder) {
+            var o = plot.getOptions();
+            if (o.zoom.interactive) {
+                eventHolder[o.zoom.trigger](onZoomClick);
+                eventHolder.mousewheel(onMouseWheel);
+            }
+
+            if (o.pan.interactive) {
+                eventHolder.bind("dragstart", { distance: 10 }, onDragStart);
+                eventHolder.bind("drag", onDrag);
+                eventHolder.bind("dragend", onDragEnd);
+            }
+        }
+
+        plot.zoomOut = function (args) {
+            if (!args)
+                args = {};
+            
+            if (!args.amount)
+                args.amount = plot.getOptions().zoom.amount
+
+            args.amount = 1 / args.amount;
+            plot.zoom(args);
+        }
+        
+        plot.zoom = function (args) {
+            if (!args)
+                args = {};
+            
+            var c = args.center,
+                amount = args.amount || plot.getOptions().zoom.amount,
+                w = plot.width(), h = plot.height();
+
+            if (!c)
+                c = { left: w / 2, top: h / 2 };
+                
+            var xf = c.left / w,
+                yf = c.top / h,
+                minmax = {
+                    x: {
+                        min: c.left - xf * w / amount,
+                        max: c.left + (1 - xf) * w / amount
+                    },
+                    y: {
+                        min: c.top - yf * h / amount,
+                        max: c.top + (1 - yf) * h / amount
+                    }
+                };
+
+            $.each(plot.getAxes(), function(_, axis) {
+                var opts = axis.options,
+                    min = minmax[axis.direction].min,
+                    max = minmax[axis.direction].max,
+                    zr = opts.zoomRange;
+
+                if (zr === false) // no zooming on this axis
+                    return;
+                    
+                min = axis.c2p(min);
+                max = axis.c2p(max);
+                if (min > max) {
+                    // make sure min < max
+                    var tmp = min;
+                    min = max;
+                    max = tmp;
+                }
+
+                var range = max - min;
+                if (zr &&
+                    ((zr[0] != null && range < zr[0]) ||
+                     (zr[1] != null && range > zr[1])))
+                    return;
+            
+                opts.min = min;
+                opts.max = max;
+            });
+            
+            plot.setupGrid();
+            plot.draw();
+            
+            if (!args.preventEvent)
+                plot.getPlaceholder().trigger("plotzoom", [ plot ]);
+        }
+
+        plot.pan = function (args) {
+            var delta = {
+                x: +args.left,
+                y: +args.top
+            };
+
+            if (isNaN(delta.x))
+                delta.x = 0;
+            if (isNaN(delta.y))
+                delta.y = 0;
+
+            $.each(plot.getAxes(), function (_, axis) {
+                var opts = axis.options,
+                    min, max, d = delta[axis.direction];
+
+                min = axis.c2p(axis.p2c(axis.min) + d),
+                max = axis.c2p(axis.p2c(axis.max) + d);
+
+                var pr = opts.panRange;
+                if (pr === false) // no panning on this axis
+                    return;
+                
+                if (pr) {
+                    // check whether we hit the wall
+                    if (pr[0] != null && pr[0] > min) {
+                        d = pr[0] - min;
+                        min += d;
+                        max += d;
+                    }
+                    
+                    if (pr[1] != null && pr[1] < max) {
+                        d = pr[1] - max;
+                        min += d;
+                        max += d;
+                    }
+                }
+                
+                opts.min = min;
+                opts.max = max;
+            });
+            
+            plot.setupGrid();
+            plot.draw();
+            
+            if (!args.preventEvent)
+                plot.getPlaceholder().trigger("plotpan", [ plot ]);
+        }
+
+        function shutdown(plot, eventHolder) {
+            eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick);
+            eventHolder.unbind("mousewheel", onMouseWheel);
+            eventHolder.unbind("dragstart", onDragStart);
+            eventHolder.unbind("drag", onDrag);
+            eventHolder.unbind("dragend", onDragEnd);
+            if (panTimeout)
+                clearTimeout(panTimeout);
+        }
+        
+        plot.hooks.bindEvents.push(bindEvents);
+        plot.hooks.shutdown.push(shutdown);
+    }
+    
+    $.plot.plugins.push({
+        init: init,
+        options: options,
+        name: 'navigate',
+        version: '1.3'
+    });
+})(jQuery);
diff --git a/js/jquery.flot.navigate.min.js b/js/jquery.flot.navigate.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..1aa03fe0ece2c4357cfa5061da66b2928eb82ea6
--- /dev/null
+++ b/js/jquery.flot.navigate.min.js
@@ -0,0 +1 @@
+LyogRmxvdCBwbHVnaW4gZm9yIGFkZGluZyB0aGUgYWJpbGl0eSB0byBwYW4gYW5kIHpvb20gdGhlIHBsb3QuCgpDb3B5cmlnaHQgKGMpIDIwMDctMjAxMyBJT0xBIGFuZCBPbGUgTGF1cnNlbi4KTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLgoKVGhlIGRlZmF1bHQgYmVoYXZpb3VyIGlzIGRvdWJsZSBjbGljayBhbmQgc2Nyb2xsd2hlZWwgdXAvZG93biB0byB6b29tIGluLCBkcmFnCnRvIHBhbi4gVGhlIHBsdWdpbiBkZWZpbmVzIHBsb3Quem9vbSh7IGNlbnRlciB9KSwgcGxvdC56b29tT3V0KCkgYW5kCnBsb3QucGFuKCBvZmZzZXQgKSBzbyB5b3UgZWFzaWx5IGNhbiBhZGQgY3VzdG9tIGNvbnRyb2xzLiBJdCBhbHNvIGZpcmVzCiJwbG90cGFuIiBhbmQgInBsb3R6b29tIiBldmVudHMsIHVzZWZ1bCBmb3Igc3luY2hyb25pemluZyBwbG90cy4KClRoZSBwbHVnaW4gc3VwcG9ydHMgdGhlc2Ugb3B0aW9uczoKCgl6b29tOiB7CgkJaW50ZXJhY3RpdmU6IGZhbHNlCgkJdHJpZ2dlcjogImRibGNsaWNrIiAvLyBvciAiY2xpY2siIGZvciBzaW5nbGUgY2xpY2sKCQlhbW91bnQ6IDEuNSAgICAgICAgIC8vIDIgPSAyMDAlICh6b29tIGluKSwgMC41ID0gNTAlICh6b29tIG91dCkKCX0KCglwYW46IHsKCQlpbnRlcmFjdGl2ZTogZmFsc2UKCQljdXJzb3I6ICJtb3ZlIiAgICAgIC8vIENTUyBtb3VzZSBjdXJzb3IgdmFsdWUgdXNlZCB3aGVuIGRyYWdnaW5nLCBlLmcuICJwb2ludGVyIgoJCWZyYW1lUmF0ZTogMjAKCX0KCgl4YXhpcywgeWF4aXMsIHgyYXhpcywgeTJheGlzOiB7CgkJem9vbVJhbmdlOiBudWxsICAvLyBvciBbIG51bWJlciwgbnVtYmVyIF0gKG1pbiByYW5nZSwgbWF4IHJhbmdlKSBvciBmYWxzZQoJCXBhblJhbmdlOiBudWxsICAgLy8gb3IgWyBudW1iZXIsIG51bWJlciBdIChtaW4sIG1heCkgb3IgZmFsc2UKCX0KCiJpbnRlcmFjdGl2ZSIgZW5hYmxlcyB0aGUgYnVpbHQtaW4gZHJhZy9jbGljayBiZWhhdmlvdXIuIElmIHlvdSBlbmFibGUKaW50ZXJhY3RpdmUgZm9yIHBhbiwgdGhlbiB5b3UnbGwgaGF2ZSBhIGJhc2ljIHBsb3QgdGhhdCBzdXBwb3J0cyBtb3ZpbmcKYXJvdW5kOyB0aGUgc2FtZSBmb3Igem9vbS4KCiJhbW91bnQiIHNwZWNpZmllcyB0aGUgZGVmYXVsdCBhbW91bnQgdG8gem9vbSBpbiAoc28gMS41ID0gMTUwJSkgcmVsYXRpdmUgdG8KdGhlIGN1cnJlbnQgdmlld3BvcnQuCgoiY3Vyc29yIiBpcyBhIHN0YW5kYXJkIENTUyBtb3VzZSBjdXJzb3Igc3RyaW5nIHVzZWQgZm9yIHZpc3VhbCBmZWVkYmFjayB0byB0aGUKdXNlciB3aGVuIGRyYWdnaW5nLgoKImZyYW1lUmF0ZSIgc3BlY2lmaWVzIHRoZSBtYXhpbXVtIG51bWJlciBvZiB0aW1lcyBwZXIgc2Vjb25kIHRoZSBwbG90IHdpbGwKdXBkYXRlIGl0c2VsZiB3aGlsZSB0aGUgdXNlciBpcyBwYW5uaW5nIGFyb3VuZCBvbiBpdCAoc2V0IHRvIG51bGwgdG8gZGlzYWJsZQppbnRlcm1lZGlhdGUgcGFucywgdGhlIHBsb3Qgd2lsbCB0aGVuIG5vdCB1cGRhdGUgdW50aWwgdGhlIG1vdXNlIGJ1dHRvbiBpcwpyZWxlYXNlZCkuCgoiem9vbVJhbmdlIiBpcyB0aGUgaW50ZXJ2YWwgaW4gd2hpY2ggem9vbWluZyBjYW4gaGFwcGVuLCBlLmcuIHdpdGggem9vbVJhbmdlOgpbMSwgMTAwXSB0aGUgem9vbSB3aWxsIG5ldmVyIHNjYWxlIHRoZSBheGlzIHNvIHRoYXQgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBtaW4KYW5kIG1heCBpcyBzbWFsbGVyIHRoYW4gMSBvciBsYXJnZXIgdGhhbiAxMDAuIFlvdSBjYW4gc2V0IGVpdGhlciBlbmQgdG8gbnVsbAp0byBpZ25vcmUsIGUuZy4gWzEsIG51bGxdLiBJZiB5b3Ugc2V0IHpvb21SYW5nZSB0byBmYWxzZSwgem9vbWluZyBvbiB0aGF0IGF4aXMKd2lsbCBiZSBkaXNhYmxlZC4KCiJwYW5SYW5nZSIgY29uZmluZXMgdGhlIHBhbm5pbmcgdG8gc3RheSB3aXRoaW4gYSByYW5nZSwgZS5nLiB3aXRoIHBhblJhbmdlOgpbLTEwLCAyMF0gcGFubmluZyBzdG9wcyBhdCAtMTAgaW4gb25lIGVuZCBhbmQgYXQgMjAgaW4gdGhlIG90aGVyLiBFaXRoZXIgY2FuCmJlIG51bGwsIGUuZy4gWy0xMCwgbnVsbF0uIElmIHlvdSBzZXQgcGFuUmFuZ2UgdG8gZmFsc2UsIHBhbm5pbmcgb24gdGhhdCBheGlzCndpbGwgYmUgZGlzYWJsZWQuCgpFeGFtcGxlIEFQSSB1c2FnZToKCglwbG90ID0gJC5wbG90KC4uLik7CgoJLy8gem9vbSBkZWZhdWx0IGFtb3VudCBpbiBvbiB0aGUgcGl4ZWwgKCAxMCwgMjAgKQoJcGxvdC56b29tKHsgY2VudGVyOiB7IGxlZnQ6IDEwLCB0b3A6IDIwIH0gfSk7CgoJLy8gem9vbSBvdXQgYWdhaW4KCXBsb3Quem9vbU91dCh7IGNlbnRlcjogeyBsZWZ0OiAxMCwgdG9wOiAyMCB9IH0pOwoKCS8vIHpvb20gMjAwJSBpbiBvbiB0aGUgcGl4ZWwgKDEwLCAyMCkKCXBsb3Quem9vbSh7IGFtb3VudDogMiwgY2VudGVyOiB7IGxlZnQ6IDEwLCB0b3A6IDIwIH0gfSk7CgoJLy8gcGFuIDEwMCBwaXhlbHMgdG8gdGhlIGxlZnQgYW5kIDIwIGRvd24KCXBsb3QucGFuKHsgbGVmdDogLTEwMCwgdG9wOiAyMCB9KQoKSGVyZSwgImNlbnRlciIgc3BlY2lmaWVzIHdoZXJlIHRoZSBjZW50ZXIgb2YgdGhlIHpvb21pbmcgc2hvdWxkIGhhcHBlbi4gTm90ZQp0aGF0IHRoaXMgaXMgZGVmaW5lZCBpbiBwaXhlbCBzcGFjZSwgbm90IHRoZSBzcGFjZSBvZiB0aGUgZGF0YSBwb2ludHMgKHlvdSBjYW4KdXNlIHRoZSBwMmMgaGVscGVycyBvbiB0aGUgYXhlcyBpbiBGbG90IHRvIGhlbHAgeW91IGNvbnZlcnQgYmV0d2VlbiB0aGVzZSkuCgoiYW1vdW50IiBpcyB0aGUgYW1vdW50IHRvIHpvb20gdGhlIHZpZXdwb3J0IHJlbGF0aXZlIHRvIHRoZSBjdXJyZW50IHJhbmdlLCBzbwoxIGlzIDEwMCUgKGkuZS4gbm8gY2hhbmdlKSwgMS41IGlzIDE1MCUgKHpvb20gaW4pLCAwLjcgaXMgNzAlICh6b29tIG91dCkuIFlvdQpjYW4gc2V0IHRoZSBkZWZhdWx0IGluIHRoZSBvcHRpb25zLgoKKi8vLyBGaXJzdCB0d28gZGVwZW5kZW5jaWVzLCBqcXVlcnkuZXZlbnQuZHJhZy5qcyBhbmQKLy8ganF1ZXJ5Lm1vdXNld2hlZWwuanMsIHdlIHB1dCB0aGVtIGlubGluZSBoZXJlIHRvIHNhdmUgcGVvcGxlIHRoZQovLyBlZmZvcnQgb2YgZG93bmxvYWRpbmcgdGhlbS4KLyoKanF1ZXJ5LmV2ZW50LmRyYWcuanMgfiB2MS41IH4gQ29weXJpZ2h0IChjKSAyMDA4LCBUaHJlZSBEdWIgTWVkaWEgKGh0dHA6Ly90aHJlZWR1Ym1lZGlhLmNvbSkKTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlIH4gaHR0cDovL3RocmVlZHVibWVkaWEuZ29vZ2xlY29kZS5jb20vZmlsZXMvTUlULUxJQ0VOU0UudHh0CiovKGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoaSl7dmFyIGwsaD10aGlzLHA9aS5kYXRhfHx7fTtpZihwLmVsZW0paD1pLmRyYWdUYXJnZXQ9cC5lbGVtLGkuZHJhZ1Byb3h5PWEucHJveHl8fGgsaS5jdXJzb3JPZmZzZXRYPXAucGFnZVgtcC5sZWZ0LGkuY3Vyc29yT2Zmc2V0WT1wLnBhZ2VZLXAudG9wLGkub2Zmc2V0WD1pLnBhZ2VYLWkuY3Vyc29yT2Zmc2V0WCxpLm9mZnNldFk9aS5wYWdlWS1pLmN1cnNvck9mZnNldFk7ZWxzZSBpZihhLmRyYWdnaW5nfHxwLndoaWNoPjAmJmkud2hpY2ghPXAud2hpY2h8fGUoaS50YXJnZXQpLmlzKHAubm90KSlyZXR1cm47c3dpdGNoKGkudHlwZSl7Y2FzZSJtb3VzZWRvd24iOnJldHVybiBlLmV4dGVuZChwLGUoaCkub2Zmc2V0KCkse2VsZW06aCx0YXJnZXQ6aS50YXJnZXQscGFnZVg6aS5wYWdlWCxwYWdlWTppLnBhZ2VZfSksby5hZGQoZG9jdW1lbnQsIm1vdXNlbW92ZSBtb3VzZXVwIix0LHApLHMoaCwhMSksYS5kcmFnZ2luZz1udWxsLCExO2Nhc2UhYS5kcmFnZ2luZyYmIm1vdXNlbW92ZSI6aWYocihpLnBhZ2VYLXAucGFnZVgpK3IoaS5wYWdlWS1wLnBhZ2VZKTxwLmRpc3RhbmNlKWJyZWFrO2kudGFyZ2V0PXAudGFyZ2V0LGw9bihpLCJkcmFnc3RhcnQiLGgpLGwhPT0hMSYmKGEuZHJhZ2dpbmc9aCxhLnByb3h5PWkuZHJhZ1Byb3h5PWUobHx8aClbMF0pO2Nhc2UibW91c2Vtb3ZlIjppZihhLmRyYWdnaW5nKXtpZihsPW4oaSwiZHJhZyIsaCksdS5kcm9wJiYodS5kcm9wLmFsbG93ZWQ9bCE9PSExLHUuZHJvcC5oYW5kbGVyKGkpKSxsIT09ITEpYnJlYWs7aS50eXBlPSJtb3VzZXVwIn07Y2FzZSJtb3VzZXVwIjpvLnJlbW92ZShkb2N1bWVudCwibW91c2Vtb3ZlIG1vdXNldXAiLHQpLGEuZHJhZ2dpbmcmJih1LmRyb3AmJnUuZHJvcC5oYW5kbGVyKGkpLG4oaSwiZHJhZ2VuZCIsaCkpLHMoaCwhMCksYS5kcmFnZ2luZz1hLnByb3h5PXAuZWxlbT0hMX1yZXR1cm4hMH1mdW5jdGlvbiBuKHQsbixyKXt0LnR5cGU9bjt2YXIgaT1lLmV2ZW50LmRpc3BhdGNoLmNhbGwocix0KTtyZXR1cm4gaT09PSExPyExOml8fHQucmVzdWx0fWZ1bmN0aW9uIHIoZSl7cmV0dXJuIE1hdGgucG93KGUsMil9ZnVuY3Rpb24gaSgpe3JldHVybiBhLmRyYWdnaW5nPT09ITF9ZnVuY3Rpb24gcyhlLHQpe2UmJihlLnVuc2VsZWN0YWJsZT10PyJvZmYiOiJvbiIsZS5vbnNlbGVjdHN0YXJ0PWZ1bmN0aW9uKCl7cmV0dXJuIHR9LGUuc3R5bGUmJihlLnN0eWxlLk1velVzZXJTZWxlY3Q9dD8iIjoibm9uZSIpKX1lLmZuLmRyYWc9ZnVuY3Rpb24oZSx0LG4pe3JldHVybiB0JiZ0aGlzLmJpbmQoImRyYWdzdGFydCIsZSksbiYmdGhpcy5iaW5kKCJkcmFnZW5kIixuKSxlP3RoaXMuYmluZCgiZHJhZyIsdD90OmUpOnRoaXMudHJpZ2dlcigiZHJhZyIpfTt2YXIgbz1lLmV2ZW50LHU9by5zcGVjaWFsLGE9dS5kcmFnPXtub3Q6IjppbnB1dCIsZGlzdGFuY2U6MCx3aGljaDoxLGRyYWdnaW5nOiExLHNldHVwOmZ1bmN0aW9uKG4pe249ZS5leHRlbmQoe2Rpc3RhbmNlOmEuZGlzdGFuY2Usd2hpY2g6YS53aGljaCxub3Q6YS5ub3R9LG58fHt9KSxuLmRpc3RhbmNlPXIobi5kaXN0YW5jZSksby5hZGQodGhpcywibW91c2Vkb3duIix0LG4pLHRoaXMuYXR0YWNoRXZlbnQmJnRoaXMuYXR0YWNoRXZlbnQoIm9uZHJhZ3N0YXJ0IixpKX0sdGVhcmRvd246ZnVuY3Rpb24oKXtvLnJlbW92ZSh0aGlzLCJtb3VzZWRvd24iLHQpLHRoaXM9PT1hLmRyYWdnaW5nJiYoYS5kcmFnZ2luZz1hLnByb3h5PSExKSxzKHRoaXMsITApLHRoaXMuZGV0YWNoRXZlbnQmJnRoaXMuZGV0YWNoRXZlbnQoIm9uZHJhZ3N0YXJ0IixpKX19O3UuZHJhZ3N0YXJ0PXUuZHJhZ2VuZD17c2V0dXA6ZnVuY3Rpb24oKXt9LHRlYXJkb3duOmZ1bmN0aW9uKCl7fX19KShqUXVlcnkpLGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQodCl7dmFyIG49dHx8d2luZG93LmV2ZW50LHI9W10uc2xpY2UuY2FsbChhcmd1bWVudHMsMSksaT0wLHM9MCxvPTAsdD1lLmV2ZW50LmZpeChuKTtyZXR1cm4gdC50eXBlPSJtb3VzZXdoZWVsIixuLndoZWVsRGVsdGEmJihpPW4ud2hlZWxEZWx0YS8xMjApLG4uZGV0YWlsJiYoaT0tbi5kZXRhaWwvMyksbz1pLHZvaWQgMCE9PW4uYXhpcyYmbi5heGlzPT09bi5IT1JJWk9OVEFMX0FYSVMmJihvPTAscz0tMSppKSx2b2lkIDAhPT1uLndoZWVsRGVsdGFZJiYobz1uLndoZWVsRGVsdGFZLzEyMCksdm9pZCAwIT09bi53aGVlbERlbHRhWCYmKHM9LTEqbi53aGVlbERlbHRhWC8xMjApLHIudW5zaGlmdCh0LGkscyxvKSwoZS5ldmVudC5kaXNwYXRjaHx8ZS5ldmVudC5oYW5kbGUpLmFwcGx5KHRoaXMscil9dmFyIG49WyJET01Nb3VzZVNjcm9sbCIsIm1vdXNld2hlZWwiXTtpZihlLmV2ZW50LmZpeEhvb2tzKWZvcih2YXIgcj1uLmxlbmd0aDtyOyllLmV2ZW50LmZpeEhvb2tzW25bLS1yXV09ZS5ldmVudC5tb3VzZUhvb2tzO2UuZXZlbnQuc3BlY2lhbC5tb3VzZXdoZWVsPXtzZXR1cDpmdW5jdGlvbigpe2lmKHRoaXMuYWRkRXZlbnRMaXN0ZW5lcilmb3IodmFyIGU9bi5sZW5ndGg7ZTspdGhpcy5hZGRFdmVudExpc3RlbmVyKG5bLS1lXSx0LCExKTtlbHNlIHRoaXMub25tb3VzZXdoZWVsPXR9LHRlYXJkb3duOmZ1bmN0aW9uKCl7aWYodGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKWZvcih2YXIgZT1uLmxlbmd0aDtlOyl0aGlzLnJlbW92ZUV2ZW50TGlzdGVuZXIoblstLWVdLHQsITEpO2Vsc2UgdGhpcy5vbm1vdXNld2hlZWw9bnVsbH19LGUuZm4uZXh0ZW5kKHttb3VzZXdoZWVsOmZ1bmN0aW9uKGUpe3JldHVybiBlP3RoaXMuYmluZCgibW91c2V3aGVlbCIsZSk6dGhpcy50cmlnZ2VyKCJtb3VzZXdoZWVsIil9LHVubW91c2V3aGVlbDpmdW5jdGlvbihlKXtyZXR1cm4gdGhpcy51bmJpbmQoIm1vdXNld2hlZWwiLGUpfX0pfShqUXVlcnkpLGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIG4odCl7ZnVuY3Rpb24gbihlLG4pe3ZhciByPXQub2Zmc2V0KCk7ci5sZWZ0PWUucGFnZVgtci5sZWZ0LHIudG9wPWUucGFnZVktci50b3Asbj90Lnpvb21PdXQoe2NlbnRlcjpyfSk6dC56b29tKHtjZW50ZXI6cn0pfWZ1bmN0aW9uIHIoZSx0KXtyZXR1cm4gZS5wcmV2ZW50RGVmYXVsdCgpLG4oZSx0PDApLCExfWZ1bmN0aW9uIGEoZSl7aWYoZS53aGljaCE9MSlyZXR1cm4hMTt2YXIgbj10LmdldFBsYWNlaG9sZGVyKCkuY3NzKCJjdXJzb3IiKTtuJiYoaT1uKSx0LmdldFBsYWNlaG9sZGVyKCkuY3NzKCJjdXJzb3IiLHQuZ2V0T3B0aW9ucygpLnBhbi5jdXJzb3IpLHM9ZS5wYWdlWCxvPWUucGFnZVl9ZnVuY3Rpb24gZihlKXt2YXIgbj10LmdldE9wdGlvbnMoKS5wYW4uZnJhbWVSYXRlO2lmKHV8fCFuKXJldHVybjt1PXNldFRpbWVvdXQoZnVuY3Rpb24oKXt0LnBhbih7bGVmdDpzLWUucGFnZVgsdG9wOm8tZS5wYWdlWX0pLHM9ZS5wYWdlWCxvPWUucGFnZVksdT1udWxsfSwxL24qMWUzKX1mdW5jdGlvbiBsKGUpe3UmJihjbGVhclRpbWVvdXQodSksdT1udWxsKSx0LmdldFBsYWNlaG9sZGVyKCkuY3NzKCJjdXJzb3IiLGkpLHQucGFuKHtsZWZ0OnMtZS5wYWdlWCx0b3A6by1lLnBhZ2VZfSl9ZnVuY3Rpb24gYyhlLHQpe3ZhciBpPWUuZ2V0T3B0aW9ucygpO2kuem9vbS5pbnRlcmFjdGl2ZSYmKHRbaS56b29tLnRyaWdnZXJdKG4pLHQubW91c2V3aGVlbChyKSksaS5wYW4uaW50ZXJhY3RpdmUmJih0LmJpbmQoImRyYWdzdGFydCIse2Rpc3RhbmNlOjEwfSxhKSx0LmJpbmQoImRyYWciLGYpLHQuYmluZCgiZHJhZ2VuZCIsbCkpfWZ1bmN0aW9uIGgoZSx0KXt0LnVuYmluZChlLmdldE9wdGlvbnMoKS56b29tLnRyaWdnZXIsbiksdC51bmJpbmQoIm1vdXNld2hlZWwiLHIpLHQudW5iaW5kKCJkcmFnc3RhcnQiLGEpLHQudW5iaW5kKCJkcmFnIixmKSx0LnVuYmluZCgiZHJhZ2VuZCIsbCksdSYmY2xlYXJUaW1lb3V0KHUpfXZhciBpPSJkZWZhdWx0IixzPTAsbz0wLHU9bnVsbDt0Lnpvb21PdXQ9ZnVuY3Rpb24oZSl7ZXx8KGU9e30pLGUuYW1vdW50fHwoZS5hbW91bnQ9dC5nZXRPcHRpb25zKCkuem9vbS5hbW91bnQpLGUuYW1vdW50PTEvZS5hbW91bnQsdC56b29tKGUpfSx0Lnpvb209ZnVuY3Rpb24obil7bnx8KG49e30pO3ZhciByPW4uY2VudGVyLGk9bi5hbW91bnR8fHQuZ2V0T3B0aW9ucygpLnpvb20uYW1vdW50LHM9dC53aWR0aCgpLG89dC5oZWlnaHQoKTtyfHwocj17bGVmdDpzLzIsdG9wOm8vMn0pO3ZhciB1PXIubGVmdC9zLGE9ci50b3AvbyxmPXt4OnttaW46ci5sZWZ0LXUqcy9pLG1heDpyLmxlZnQrKDEtdSkqcy9pfSx5OnttaW46ci50b3AtYSpvL2ksbWF4OnIudG9wKygxLWEpKm8vaX19O2UuZWFjaCh0LmdldEF4ZXMoKSxmdW5jdGlvbihlLHQpe3ZhciBuPXQub3B0aW9ucyxyPWZbdC5kaXJlY3Rpb25dLm1pbixpPWZbdC5kaXJlY3Rpb25dLm1heCxzPW4uem9vbVJhbmdlLG89bi5wYW5SYW5nZTtpZihzPT09ITEpcmV0dXJuO3I9dC5jMnAociksaT10LmMycChpKTtpZihyPmkpe3ZhciB1PXI7cj1pLGk9dX1vJiYob1swXSE9bnVsbCYmcjxvWzBdJiYocj1vWzBdKSxvWzFdIT1udWxsJiZpPm9bMV0mJihpPW9bMV0pKTt2YXIgYT1pLXI7aWYocyYmKHNbMF0hPW51bGwmJmE8c1swXXx8c1sxXSE9bnVsbCYmYT5zWzFdKSlyZXR1cm47bi5taW49cixuLm1heD1pfSksdC5zZXR1cEdyaWQoKSx0LmRyYXcoKSxuLnByZXZlbnRFdmVudHx8dC5nZXRQbGFjZWhvbGRlcigpLnRyaWdnZXIoInBsb3R6b29tIixbdCxuXSl9LHQucGFuPWZ1bmN0aW9uKG4pe3ZhciByPXt4OituLmxlZnQseTorbi50b3B9O2lzTmFOKHIueCkmJihyLng9MCksaXNOYU4oci55KSYmKHIueT0wKSxlLmVhY2godC5nZXRBeGVzKCksZnVuY3Rpb24oZSx0KXt2YXIgbj10Lm9wdGlvbnMsaSxzLG89clt0LmRpcmVjdGlvbl07aT10LmMycCh0LnAyYyh0Lm1pbikrbykscz10LmMycCh0LnAyYyh0Lm1heCkrbyk7dmFyIHU9bi5wYW5SYW5nZTtpZih1PT09ITEpcmV0dXJuO3UmJih1WzBdIT1udWxsJiZ1WzBdPmkmJihvPXVbMF0taSxpKz1vLHMrPW8pLHVbMV0hPW51bGwmJnVbMV08cyYmKG89dVsxXS1zLGkrPW8scys9bykpLG4ubWluPWksbi5tYXg9c30pLHQuc2V0dXBHcmlkKCksdC5kcmF3KCksbi5wcmV2ZW50RXZlbnR8fHQuZ2V0UGxhY2Vob2xkZXIoKS50cmlnZ2VyKCJwbG90cGFuIixbdCxuXSl9LHQuaG9va3MuYmluZEV2ZW50cy5wdXNoKGMpLHQuaG9va3Muc2h1dGRvd24ucHVzaChoKX12YXIgdD17eGF4aXM6e3pvb21SYW5nZTpudWxsLHBhblJhbmdlOm51bGx9LHpvb206e2ludGVyYWN0aXZlOiExLHRyaWdnZXI6ImRibGNsaWNrIixhbW91bnQ6MS41fSxwYW46e2ludGVyYWN0aXZlOiExLGN1cnNvcjoibW92ZSIsZnJhbWVSYXRlOjIwfX07ZS5wbG90LnBsdWdpbnMucHVzaCh7aW5pdDpuLG9wdGlvbnM6dCxuYW1lOiJuYXZpZ2F0ZSIsdmVyc2lvbjoiMS4zIn0pfShqUXVlcnkpOw==
\ No newline at end of file
diff --git a/js/jquery.flot.selection.js b/js/jquery.flot.selection.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f7b32694bda98c39b5f4af4ef54835c72d41dbb
--- /dev/null
+++ b/js/jquery.flot.selection.js
@@ -0,0 +1,344 @@
+/*
+Flot plugin for selecting regions.
+
+The plugin defines the following options:
+
+  selection: {
+    mode: null or "x" or "y" or "xy",
+    color: color
+  }
+
+Selection support is enabled by setting the mode to one of "x", "y" or
+"xy". In "x" mode, the user will only be able to specify the x range,
+similarly for "y" mode. For "xy", the selection becomes a rectangle
+where both ranges can be specified. "color" is color of the selection
+(if you need to change the color later on, you can get to it with
+plot.getOptions().selection.color).
+
+When selection support is enabled, a "plotselected" event will be
+emitted on the DOM element you passed into the plot function. The
+event handler gets a parameter with the ranges selected on the axes,
+like this:
+
+  placeholder.bind("plotselected", function(event, ranges) {
+    alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
+    // similar for yaxis - with multiple axes, the extra ones are in
+    // x2axis, x3axis, ...
+  });
+
+The "plotselected" event is only fired when the user has finished
+making the selection. A "plotselecting" event is fired during the
+process with the same parameters as the "plotselected" event, in case
+you want to know what's happening while it's happening,
+
+A "plotunselected" event with no arguments is emitted when the user
+clicks the mouse to remove the selection.
+
+The plugin allso adds the following methods to the plot object:
+
+- setSelection(ranges, preventEvent)
+
+  Set the selection rectangle. The passed in ranges is on the same
+  form as returned in the "plotselected" event. If the selection mode
+  is "x", you should put in either an xaxis range, if the mode is "y"
+  you need to put in an yaxis range and both xaxis and yaxis if the
+  selection mode is "xy", like this:
+
+    setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
+
+  setSelection will trigger the "plotselected" event when called. If
+  you don't want that to happen, e.g. if you're inside a
+  "plotselected" handler, pass true as the second parameter. If you
+  are using multiple axes, you can specify the ranges on any of those,
+  e.g. as x2axis/x3axis/... instead of xaxis, the plugin picks the
+  first one it sees.
+  
+- clearSelection(preventEvent)
+
+  Clear the selection rectangle. Pass in true to avoid getting a
+  "plotunselected" event.
+
+- getSelection()
+
+  Returns the current selection in the same format as the
+  "plotselected" event. If there's currently no selection, the
+  function returns null.
+
+*/
+
+(function ($) {
+    function init(plot) {
+        var selection = {
+                first: { x: -1, y: -1}, second: { x: -1, y: -1},
+                show: false,
+                active: false
+            };
+
+        // FIXME: The drag handling implemented here should be
+        // abstracted out, there's some similar code from a library in
+        // the navigation plugin, this should be massaged a bit to fit
+        // the Flot cases here better and reused. Doing this would
+        // make this plugin much slimmer.
+        var savedhandlers = {};
+
+        var mouseUpHandler = null;
+        
+        function onMouseMove(e) {
+            if (selection.active) {
+                updateSelection(e);
+                
+                plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
+            }
+        }
+
+        function onMouseDown(e) {
+            if (e.which != 1)  // only accept left-click
+                return;
+            
+            // cancel out any text selections
+            document.body.focus();
+
+            // prevent text selection and drag in old-school browsers
+            if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
+                savedhandlers.onselectstart = document.onselectstart;
+                document.onselectstart = function () { return false; };
+            }
+            if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
+                savedhandlers.ondrag = document.ondrag;
+                document.ondrag = function () { return false; };
+            }
+
+            setSelectionPos(selection.first, e);
+
+            selection.active = true;
+
+            // this is a bit silly, but we have to use a closure to be
+            // able to whack the same handler again
+            mouseUpHandler = function (e) { onMouseUp(e); };
+            
+            $(document).one("mouseup", mouseUpHandler);
+        }
+
+        function onMouseUp(e) {
+            mouseUpHandler = null;
+            
+            // revert drag stuff for old-school browsers
+            if (document.onselectstart !== undefined)
+                document.onselectstart = savedhandlers.onselectstart;
+            if (document.ondrag !== undefined)
+                document.ondrag = savedhandlers.ondrag;
+
+            // no more dragging
+            selection.active = false;
+            updateSelection(e);
+
+            if (selectionIsSane())
+                triggerSelectedEvent();
+            else {
+                // this counts as a clear
+                plot.getPlaceholder().trigger("plotunselected", [ ]);
+                plot.getPlaceholder().trigger("plotselecting", [ null ]);
+            }
+
+            return false;
+        }
+
+        function getSelection() {
+            if (!selectionIsSane())
+                return null;
+
+            var r = {}, c1 = selection.first, c2 = selection.second;
+            $.each(plot.getAxes(), function (name, axis) {
+                if (axis.used) {
+                    var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]); 
+                    r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
+                }
+            });
+            return r;
+        }
+
+        function triggerSelectedEvent() {
+            var r = getSelection();
+
+            plot.getPlaceholder().trigger("plotselected", [ r ]);
+
+            // backwards-compat stuff, to be removed in future
+            if (r.xaxis && r.yaxis)
+                plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
+        }
+
+        function clamp(min, value, max) {
+            return value < min ? min: (value > max ? max: value);
+        }
+
+        function setSelectionPos(pos, e) {
+            var o = plot.getOptions();
+            var offset = plot.getPlaceholder().offset();
+            var plotOffset = plot.getPlotOffset();
+            pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
+            pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
+
+            if (o.selection.mode == "y")
+                pos.x = pos == selection.first ? 0 : plot.width();
+
+            if (o.selection.mode == "x")
+                pos.y = pos == selection.first ? 0 : plot.height();
+        }
+
+        function updateSelection(pos) {
+            if (pos.pageX == null)
+                return;
+
+            setSelectionPos(selection.second, pos);
+            if (selectionIsSane()) {
+                selection.show = true;
+                plot.triggerRedrawOverlay();
+            }
+            else
+                clearSelection(true);
+        }
+
+        function clearSelection(preventEvent) {
+            if (selection.show) {
+                selection.show = false;
+                plot.triggerRedrawOverlay();
+                if (!preventEvent)
+                    plot.getPlaceholder().trigger("plotunselected", [ ]);
+            }
+        }
+
+        // function taken from markings support in Flot
+        function extractRange(ranges, coord) {
+            var axis, from, to, key, axes = plot.getAxes();
+
+            for (var k in axes) {
+                axis = axes[k];
+                if (axis.direction == coord) {
+                    key = coord + axis.n + "axis";
+                    if (!ranges[key] && axis.n == 1)
+                        key = coord + "axis"; // support x1axis as xaxis
+                    if (ranges[key]) {
+                        from = ranges[key].from;
+                        to = ranges[key].to;
+                        break;
+                    }
+                }
+            }
+
+            // backwards-compat stuff - to be removed in future
+            if (!ranges[key]) {
+                axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
+                from = ranges[coord + "1"];
+                to = ranges[coord + "2"];
+            }
+
+            // auto-reverse as an added bonus
+            if (from != null && to != null && from > to) {
+                var tmp = from;
+                from = to;
+                to = tmp;
+            }
+            
+            return { from: from, to: to, axis: axis };
+        }
+        
+        function setSelection(ranges, preventEvent) {
+            var axis, range, o = plot.getOptions();
+
+            if (o.selection.mode == "y") {
+                selection.first.x = 0;
+                selection.second.x = plot.width();
+            }
+            else {
+                range = extractRange(ranges, "x");
+
+                selection.first.x = range.axis.p2c(range.from);
+                selection.second.x = range.axis.p2c(range.to);
+            }
+
+            if (o.selection.mode == "x") {
+                selection.first.y = 0;
+                selection.second.y = plot.height();
+            }
+            else {
+                range = extractRange(ranges, "y");
+
+                selection.first.y = range.axis.p2c(range.from);
+                selection.second.y = range.axis.p2c(range.to);
+            }
+
+            selection.show = true;
+            plot.triggerRedrawOverlay();
+            if (!preventEvent && selectionIsSane())
+                triggerSelectedEvent();
+        }
+
+        function selectionIsSane() {
+            var minSize = 5;
+            return Math.abs(selection.second.x - selection.first.x) >= minSize &&
+                Math.abs(selection.second.y - selection.first.y) >= minSize;
+        }
+
+        plot.clearSelection = clearSelection;
+        plot.setSelection = setSelection;
+        plot.getSelection = getSelection;
+
+        plot.hooks.bindEvents.push(function(plot, eventHolder) {
+            var o = plot.getOptions();
+            if (o.selection.mode != null) {
+                eventHolder.mousemove(onMouseMove);
+                eventHolder.mousedown(onMouseDown);
+            }
+        });
+
+
+        plot.hooks.drawOverlay.push(function (plot, ctx) {
+            // draw selection
+            if (selection.show && selectionIsSane()) {
+                var plotOffset = plot.getPlotOffset();
+                var o = plot.getOptions();
+
+                ctx.save();
+                ctx.translate(plotOffset.left, plotOffset.top);
+
+                var c = $.color.parse(o.selection.color);
+
+                ctx.strokeStyle = c.scale('a', 0.8).toString();
+                ctx.lineWidth = 1;
+                ctx.lineJoin = "round";
+                ctx.fillStyle = c.scale('a', 0.4).toString();
+
+                var x = Math.min(selection.first.x, selection.second.x),
+                    y = Math.min(selection.first.y, selection.second.y),
+                    w = Math.abs(selection.second.x - selection.first.x),
+                    h = Math.abs(selection.second.y - selection.first.y);
+
+                ctx.fillRect(x, y, w, h);
+                ctx.strokeRect(x, y, w, h);
+
+                ctx.restore();
+            }
+        });
+        
+        plot.hooks.shutdown.push(function (plot, eventHolder) {
+            eventHolder.unbind("mousemove", onMouseMove);
+            eventHolder.unbind("mousedown", onMouseDown);
+            
+            if (mouseUpHandler)
+                $(document).unbind("mouseup", mouseUpHandler);
+        });
+
+    }
+
+    $.plot.plugins.push({
+        init: init,
+        options: {
+            selection: {
+                mode: null, // one of null, "x", "y" or "xy"
+                color: "#e8cfac"
+            }
+        },
+        name: 'selection',
+        version: '1.1'
+    });
+})(jQuery);