diff --git a/package.json b/package.json
index b77e4b51f2b910cd329cd298141aca11a0044ce4..998af5cb6df043f09510e61f81481651ac74e041 100644
--- a/package.json
+++ b/package.json
@@ -3,10 +3,12 @@
   "version": "1.0.0",
   "private": true,
   "dependencies": {
+    "@popperjs/core": "^2.11.4",
     "@testing-library/jest-dom": "^5.14.1",
     "@testing-library/react": "^12.0.0",
     "@testing-library/user-event": "^13.2.1",
     "@types/jest": "^27.0.1",
+    "@types/lodash": "^4.14.118",
     "@types/node": "^16.7.13",
     "@types/react": "^17.0.38",
     "@types/react-dom": "^17.0.11",
@@ -14,12 +16,19 @@
     "@types/sortablejs": "^1.10.7",
     "axios": "^0.25.0",
     "bootstrap": "^5.1.3",
+    "chart.js": "^3.4.0",
+    "chartjs-plugin-datalabels": "^2.0.0",
+    "dom-to-image": "^2.6.0",
+    "file-saver": "^2.0.5",
+    "lodash": "^4.17.11",
     "moment": "^2.29.1",
     "react": "^17.0.2",
+    "react-chartjs-2": "^3.0.3",
     "react-confirm-alert": "^2.7.0",
     "react-dom": "^17.0.2",
     "react-loadable": "^5.5.0",
     "react-localization": "^1.0.17",
+    "react-modal": "^3.14.4",
     "react-router-dom": "5.2.0",
     "react-scripts": "5.0.0",
     "react-toastify": "^8.1.0",
diff --git a/src/Router.js b/src/Router.js
index 5c8c7f1545aa9266ab6acebca312d3f9908ff108..d3f49600352490827eeee5f9397d98dc102f7b71 100644
--- a/src/Router.js
+++ b/src/Router.js
@@ -15,7 +15,8 @@ import {
   ReviewApplication,
   InspectionSummary,
   InspectionComplete,
-  ViewConsentApplications
+  ViewConsentApplications,
+  Landing,
 } from "./pages";
 // import ReviewerApplications from "./pages/Reviewer/ReviewerApplications";
 import { Manage } from "./pages/Reviewer/manage";
@@ -31,6 +32,7 @@ const Router = (props) => (
       <Route exact path="/" component={Login} />
       <Route path="/login" component={Login} />
       <PrivateRoute path="/dashboard" component={Dashboard} />
+      <PrivateRoute path="/analytics" component={Landing} />
       <PrivateRoute exact path="/forms" component={ListForms} />
       <PrivateRoute exact path="/forms/add" component={AddForm} />
       <PrivateRoute exact path="/forms/:id/edit" component={AddForm} />
@@ -52,7 +54,7 @@ const Router = (props) => (
         path="/inspector/:id/:applicationId"
         component={ViewApplications}
       />
-       <PrivateRoute
+      <PrivateRoute
         exact
         path="/assisting-inspector/:id/:applicationId"
         component={ViewConsentApplications}
diff --git a/src/components/charts/BarChart.js b/src/components/charts/BarChart.js
new file mode 100644
index 0000000000000000000000000000000000000000..86859a908c8e8238e3a6e6d736ab4c5e716b8cfd
--- /dev/null
+++ b/src/components/charts/BarChart.js
@@ -0,0 +1,176 @@
+import React from "react";
+import { Bar } from "react-chartjs-2";
+import NFormatterFun from "./NFormatterFun";
+import _ from "lodash";
+import barPalette from "./palette";
+
+/**
+ * BarChart component
+ */
+
+const options = {
+  scales: {
+    y: {
+      grid: {
+        display: true,
+      },
+      ticks: {
+        font: {
+          family: "Lato-Regular",
+          size: 12,
+          lineHeight: 1.333,
+        },
+      },
+    },
+    x: {
+      grid: {
+        display: true,
+      },
+      ticks: {
+        font: {
+          family: "Lato-Regular",
+          size: 12,
+          lineHeight: 1.333,
+        },
+      },
+    },
+  },
+  responsive: true,
+  options: {
+    responsive: true,
+    maintainAspectRatio: true,
+  },
+  plugins: {
+    legend: {
+      position: "bottom",
+      display: true,
+      labels: {
+        font: {
+          family: "Lato-Regular",
+          size: 14,
+          lineHeight: 1.429,
+        },
+      },
+    },
+    datalabels: {
+      anchor: "end",
+      align: "end",
+    },
+  },
+};
+
+class BarChart extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      trigger: "",
+      chartsGData: {},
+      isData: false,
+    };
+  }
+
+  manupulateData(chartData) {
+    var barTempData = {
+      labels: [],
+      datasets: [],
+    };
+    let colors = barPalette("cb-BasePalette2", chartData.length).map(function (
+      hex
+    ) {
+      return "#" + hex;
+    });
+    chartData.forEach((d, i) => {
+      let barTempObj = {
+        label: "",
+        borderColor: colors[i],
+        backgroundColor: colors[i],
+        fill: false,
+      };
+      let tempdataArr = [];
+      let tempdatalabel = [],
+        tempVal = "";
+      barTempObj.label = d.headerName;
+      d.plots.forEach((d1, i) => {
+        tempVal = NFormatterFun(d1.value, d1.symbol, "Unit");
+        tempVal =
+          typeof tempVal == "string"
+            ? parseFloat(tempVal.replace(/,/g, ""))
+            : tempVal;
+        tempdataArr.push(d1.value);
+        if (d1.name.length > 20) {
+          tempdatalabel.push(d1.name.match(/.{1,20}\S+\s*/g));
+        } else {
+          tempdatalabel.push(d1.name);
+        }
+      });
+      barTempObj.data = tempdataArr;
+      barTempData.labels = tempdatalabel;
+      barTempData.datasets.push(barTempObj);
+    });
+
+    return barTempData;
+  }
+
+  contextMenu = (e) => {
+    e.preventDefault();
+
+    this.setState({
+      isData: false,
+    });
+  };
+
+  render() {
+    let { chartData } = this.props;
+    let { drillDownId } = this.props;
+    let data;
+
+    /*
+     * Drilldown chart data
+     */
+    let drillDownData = _.chain(this.state.chartsGData)
+      .get(drillDownId)
+      .get("data")
+      .value();
+
+    /*
+     * Condition to load drill down datasets
+     * if user enabled the drill down feature
+     */
+    if (this.state.isData) {
+      if (drillDownData !== undefined) {
+        data = this.manupulateData(drillDownData);
+      } else {
+        data = this.manupulateData(chartData);
+      }
+    } else {
+      data = this.manupulateData(chartData);
+    }
+
+    if (data) {
+      return (
+        <div onContextMenu={this.contextMenu}>
+          <Bar
+            height={this.props.dimensions.height}
+            style={{ fill: "none" }}
+            data={data}
+            options={options}
+            plugins={[
+              {
+                beforeInit: (chart, options) => {
+                  chart.legend.afterFit = () => {
+                    if (chart.legend.margins) {
+                      chart.legend.options.labels.padding = 20;
+                    }
+                  };
+                },
+              },
+            ]}
+          ></Bar>
+        </div>
+      );
+    }
+    return <div>Loading...</div>;
+  }
+}
+
+export default BarChart;
diff --git a/src/components/charts/ChartType.js b/src/components/charts/ChartType.js
new file mode 100644
index 0000000000000000000000000000000000000000..d7c5b875bdd7b1e9f581855c3916368eac55c33a
--- /dev/null
+++ b/src/components/charts/ChartType.js
@@ -0,0 +1,187 @@
+import React from "react";
+import LineChart from "./LineChart";
+import BarChart from "./BarChart";
+import PieChart from "./PieChart";
+import MixedData from "./MixedData";
+import MetricVisual from "./MetricVisual";
+import _ from "lodash";
+import { ChartService } from "../../services";
+import ExportChart from "../../helpers/exportChart";
+import moment from "moment";
+
+/**
+ * Component to genearte the required charts
+ * as per the response from the API
+ */
+
+class ChartType extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      chartsGData: {},
+    };
+  }
+
+  componentDidMount() {
+    this.callAPI();
+  }
+
+  callAPI() {
+    let code = _.chain(this.props).get("chartData").first().get("id").value();
+
+    let startRange = moment().startOf("month");
+    let endRange = moment().endOf("month");
+    startRange = Number(startRange);
+    endRange = Number(endRange);
+    let thisMonth = { startDate: startRange, endDate: endRange };
+
+    let payload = {
+      RequestInfo: {
+        authToken: "null",
+      },
+      headers: {
+        tenantId: "null",
+      },
+      aggregationRequestDto: {
+        dashboardId: "home",
+        visualizationType: "METRIC",
+        visualizationCode: code,
+        queryType: "",
+        filters: {},
+        moduleLevel: "",
+        aggregationFactors: null,
+        requestDate: thisMonth,
+      },
+    };
+
+    ChartService.getChartData(payload).then(
+      (response) => {
+        this.setState((prevState) => ({
+          ...prevState,
+          chartsGData: {
+            ...prevState.chartsGData,
+            [code]: response.responseData,
+          },
+        }));
+      },
+      (error) => {}
+    );
+  }
+
+  render() {
+    let chartKey = _.chain(this.props)
+      .get("chartData")
+      .first()
+      .get("id")
+      .value();
+
+    let chartType = _.chain(this.props)
+      .get("chartData")
+      .first()
+      .get("chartType")
+      .toUpper()
+      .value();
+
+    let data = _.chain(this.state)
+      .get("chartsGData")
+      .get(chartKey)
+      .get("data")
+      .value();
+
+    let filter = _.chain(this.props)
+      .get("chartData")
+      .first()
+      .get("filter")
+      .value();
+
+    let deepFilter = _.chain(this.state)
+      .get("chartsGData")
+      .get(chartKey)
+      .get("filter")
+      .value();
+
+    let drillDownId = _.chain(this.state)
+      .get("chartsGData")
+      .get(chartKey)
+      .get("drillDownChartId")
+      .value();
+
+    if (filter) {
+      localStorage.setItem("filterKey", filter);
+    } else if (deepFilter) {
+      localStorage.setItem("filterKey", deepFilter);
+    }
+
+    if (data) {
+      ExportChart.setAttribute(chartKey, data);
+
+      switch (chartType) {
+        case "PIE":
+          return (
+            <PieChart
+              chartData={data}
+              label={this.props.label}
+              unit={this.state.unit}
+              GFilterData={this.props.GFilterData}
+              dimensions={this.props.dimensions}
+              section={this.props.section}
+              pathName={this.props.pathName.pathProps}
+            />
+          );
+        case "LINE":
+          return (
+            <LineChart
+              chartData={data}
+              label={this.props.label}
+              unit={this.state.unit}
+              GFilterData={this.props.GFilterData}
+              dimensions={this.props.dimensions}
+              section={this.props.section}
+              pathName={this.props.pathName.pathProps}
+            />
+          );
+        case "BAR":
+          return (
+            <BarChart
+              chartData={data}
+              label={this.props.label}
+              unit={this.state.unit}
+              GFilterData={this.props.GFilterData}
+              dimensions={this.props.dimensions}
+              section={this.props.section}
+              pathName={this.props.pathName.pathProps}
+              drillDownId={drillDownId}
+              filter={filter}
+            />
+          );
+        case "LINE_BAR":
+          return (
+            <MixedData
+              chartData={data}
+              label={this.props.label}
+              unit={this.state.unit}
+              GFilterData={this.props.GFilterData}
+              dimensions={this.props.dimensions}
+              section={this.props.section}
+            />
+          );
+        case "METRICCOLLECTION":
+          return (
+            <MetricVisual
+              chartData={data}
+              label={this.props.label}
+              unit={this.state.unit}
+              GFilterData={this.props.GFilterData}
+              dimensions={this.props.dimensions}
+              section={this.props.section}
+            />
+          );
+        default:
+          return false;
+      }
+    }
+    return <div> Loading... </div>;
+  }
+}
+
+export default ChartType;
diff --git a/src/components/charts/GenericCharts.js b/src/components/charts/GenericCharts.js
new file mode 100644
index 0000000000000000000000000000000000000000..6f2d361bab6f77fb450cf1aa08a26a7deb3c7a8c
--- /dev/null
+++ b/src/components/charts/GenericCharts.js
@@ -0,0 +1,353 @@
+import React from "react";
+import ChartType from "./ChartType";
+import "file-saver";
+import domtoimage from "dom-to-image";
+import Modal from "react-modal";
+import ExportChart from "../../helpers/exportChart";
+import _ from "lodash";
+import "../../styles/chart.css";
+
+/**
+ * GenericChart component to display the
+ * generated charttypes in the page layout
+ */
+
+Modal.setAppElement("#root");
+
+class GenericCharts extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      modalData: {
+        name: "",
+        data: [],
+        chartDataName: "",
+        dimensions: "",
+      },
+      modalIsOpen: false,
+      imageBlob: "",
+      imageBase64: "",
+      s3URL: "",
+      telegramURL: "",
+      chartCode: "",
+      chartDType: "",
+    };
+    this.getModalData = this.getModalData.bind(this);
+    this.openModal = this.openModal.bind(this);
+    this.closeModal = this.closeModal.bind(this);
+    this.afterOpenModal = this.afterOpenModal.bind(this);
+  }
+
+  filterImage = (node) => {
+    return (
+      node.id !== "dropdownMenuButton" &&
+      node.id !== "zoomIn" &&
+      node.id !== "zoomOut" &&
+      node.id !== "zoomInBtn" &&
+      node.id !== "zoomOutBtn" &&
+      node.id !== "fullScreenBtn"
+    );
+  };
+
+  filterImageTwo = (node) => {
+    return (
+      node.id !== "exit" &&
+      node.id !== "downloadAsData" &&
+      node.id !== "downloadAsImage" &&
+      node.id !== "dropdownMenuButtonShare" &&
+      node.id !== "fullScreenBtn"
+    );
+  };
+
+  openModal = () => {
+    this.setState({
+      modalIsOpen: true,
+    });
+  };
+
+  afterOpenModal = () => {};
+
+  closeModal = () => {
+    this.setState({
+      modalIsOpen: false,
+    });
+  };
+
+  getModalData = (name, description, data, cdName, dimensions) => {
+    // console.log(name, data, cdName);
+    this.setState(
+      {
+        modalData: {
+          ...this.state.modalData,
+          name: name,
+          description: description,
+          data: data,
+          chartDataName: cdName,
+          dimensions: dimensions,
+        },
+        showModal: true,
+        chartCode: _.chain(data).first().get("id").value(),
+        chartDType: _.chain(data).first().get("chartType").toUpper().value(),
+      },
+      () => {
+        this.openModal();
+      }
+    );
+  };
+
+  renderCharts(d, chartData, index) {
+    switch (d.vizType.toUpperCase()) {
+      case "CHART":
+        return (
+          <div
+            key={index}
+            className={`col-sm-12 col-md-${d.dimensions.width} col-lg-${d.dimensions.width} mt-2 mb-3`}
+          >
+            <div
+              className="chart-wrapper h-100 chart_card_one chart-wrapper-padding-2"
+              id={d.name}
+            >
+              <div className="clearfix mb-3">
+                <div className="float-start">
+                  <h5 className="pt-1 chart_title_one mb-0">{d.name}</h5>
+                  {d.description && (
+                    <label className="chart_card_description_one">
+                      {d.description}
+                    </label>
+                  )}
+                </div>
+                <div className="float-end">
+                  <div className="d-flex">
+                    <div
+                      id="fullScreenBtn"
+                      className="material-icons custom_cursor mt-2 black-60"
+                      onClick={() => {
+                        this.getModalData(
+                          d.name,
+                          d.description,
+                          d.charts,
+                          chartData.name,
+                          d.dimensions
+                        );
+                      }}
+                    >
+                      fullscreen
+                    </div>
+                    <div className="dropdown">
+                      <div
+                        className="material-icons custom_cursor mt-2 ms-2 black-60"
+                        id="dropdownMenuButton"
+                        data-bs-toggle="dropdown"
+                        aria-expanded="false"
+                      >
+                        more_vert
+                      </div>
+                      <div
+                        className="dropdown-menu dropdown-menu-custom p-0 m-0"
+                        aria-labelledby="dropdownMenuButton"
+                      >
+                        <p
+                          className="dropdown-item custom_cursor dropdown_text mt-3"
+                          onClick={() =>
+                            setTimeout(() => {
+                              domtoimage
+                                .toBlob(document.getElementById(d.name), {
+                                  filter: this.filterImage,
+                                })
+                                .then((blob) => window.saveAs(blob, d.name));
+                            }, 250)
+                          }
+                        >
+                          Download as PNG
+                        </p>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+
+              {/* Modal */}
+              <Modal
+                id="modalView"
+                isOpen={this.state.modalIsOpen}
+                onAfterOpen={this.afterOpenModal}
+                onRequestClose={this.closeModal}
+                contentLabel={this.state.modalData.name}
+                className="custom-modal"
+                bodyOpenClassName="afterOpen"
+                overlayClassName="custom-modal-overlay"
+              >
+                <div>
+                  <div className="clearfix">
+                    <div className="float-start"></div>
+                    <div className="float-end custom-modal-font-2">
+                      <div className="d-flex">
+                        <div
+                          id="downloadAsImage"
+                          className="custom_cursor "
+                          onClick={() =>
+                            domtoimage
+                              .toBlob(document.getElementById("modalView"), {
+                                filter: this.filterImageTwo,
+                              })
+                              .then((blob) => {
+                                this.setState(
+                                  {
+                                    imageBlob: blob,
+                                  },
+                                  () => {
+                                    let reader = new FileReader();
+                                    reader.readAsDataURL(this.state.imageBlob);
+
+                                    reader.onload = function () {
+                                      this.image = reader.result;
+                                    };
+                                    window.saveAs(
+                                      this.state.imageBlob,
+                                      this.state.modalData.name
+                                    );
+                                  }
+                                );
+                              })
+                          }
+                        >
+                          <span className="float-end  me-3">
+                            Download as image
+                          </span>
+                          <span className="material-icons float-end me-2">
+                            cloud_download
+                          </span>
+                        </div>
+
+                        <div className="custom_cursor " id="downloadAsData">
+                          <span
+                            className="float-end me-3"
+                            onClick={() =>
+                              this.state.chartDType === "TABLE"
+                                ? ExportChart.tableToCsv(
+                                    this.state.modalData.name
+                                  )
+                                : ExportChart.toCsv(
+                                    this.state.modalData.name,
+                                    this.state.chartCode
+                                  )
+                            }
+                          >
+                            Download data
+                          </span>
+                        </div>
+                        <div
+                          className="custom_cursor "
+                          onClick={this.closeModal}
+                          id="exit"
+                        >
+                          <span className="float-end">Exit</span>
+                          <span className="material-icons float-right me-1">
+                            fullscreen_exit
+                          </span>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <h2 className="chart-header-style-1">
+                    {this.state.modalData.name}
+                  </h2>
+                  {this.state.modalData.description && (
+                    <label className="chart-desc-style-1 pb-3">
+                      {this.state.modalData.description}
+                    </label>
+                  )}
+                </div>
+
+                <div className="col-xs-12 col-sm-12 col-md-9 col-lg-8 col-xl-12 centerAlign">
+                  <ChartType
+                    key={index}
+                    chartData={this.state.modalData.data}
+                    label={this.state.modalData.name}
+                    section={this.state.modalData.chartDataName}
+                    pathName={this.props}
+                    dimensions={this.state.modalData.dimensions}
+                  />
+                </div>
+              </Modal>
+
+              {/* Visualisation */}
+              <ChartType
+                key={index}
+                chartData={d.charts}
+                label={d.name}
+                section={chartData.name}
+                pathName={this.props}
+                dimensions={d.dimensions}
+              />
+            </div>
+          </div>
+        );
+      case "METRICCOLLECTION":
+        return (
+          <div
+            key={index}
+            className={`col-sm-12 col-md-${d.dimensions.width} col-lg-${d.dimensions.width} mt-2 mb-3`}
+          >
+            <div
+              className="chart-wrapper h-100 cardChart chartWrapperPadding"
+              id={d.name}
+            >
+              <div className="row">
+                <h5 className="pb-5 pt-2 pl-3">{d.name}</h5>
+                <img
+                  className="custom_cursor mt-3 downloadBtn downloadIcon ml-3"
+                  src="data:image/png;base64,R0lGODlhFAAUAIAAAP///wAAACH5BAEAAAAALAAAAAAUABQAAAIRhI+py+0Po5y02ouz3rz7rxUAOw=="
+                  title="Download as PNG"
+                  alt="download chart"
+                  width="13"
+                  height="13"
+                  id="dropdownMenuButton"
+                  data-bs-toggle="dropdown"
+                ></img>
+                <div
+                  className="dropdown-menu dropdown-menu-custom"
+                  aria-labelledby="dropdownMenuButton"
+                  style={{ marginLeft: "-11.85em" }}
+                >
+                  <p
+                    className="dropdown-item custom_cursor  metricTextColor"
+                    onClick={() =>
+                      setTimeout(() => {
+                        domtoimage
+                          .toBlob(document.getElementById(d.name), {
+                            filter: this.filterImage,
+                          })
+                          .then((blob) => window.saveAs(blob, d.name));
+                      }, 250)
+                    }
+                  >
+                    Download as PNG
+                  </p>
+                </div>
+              </div>
+              <ChartType
+                key={index}
+                chartData={d.charts}
+                label={d.name}
+                section={chartData.name}
+              />
+            </div>
+          </div>
+        );
+      default:
+        return <div></div>;
+    }
+  }
+  render() {
+    let { chartData, row } = this.props;
+
+    return (
+      <div key={row} className="row">
+        {chartData.vizArray.map((d, i) => this.renderCharts(d, chartData, i))}
+      </div>
+    );
+  }
+}
+
+export default GenericCharts;
diff --git a/src/components/charts/LineChart.js b/src/components/charts/LineChart.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f272200328d35badbd2f7d2dfce667a3dfaf866
--- /dev/null
+++ b/src/components/charts/LineChart.js
@@ -0,0 +1,178 @@
+//Line Chart
+import React from "react";
+import { Line } from "react-chartjs-2";
+import NFormatterFun from "./NFormatterFun";
+import linePalette from "./palette";
+
+/**
+ * LineChart component
+ */
+
+const options = {
+  elements: {
+    point: {
+      radius: 0,
+    },
+    line: {
+      tension: 0,
+    },
+  },
+  scales: {
+    y: {
+      grid: {
+        display: true,
+      },
+      ticks: {
+        font: {
+          family: "Lato-Regular",
+          size: 12,
+          lineHeight: 1.333,
+        },
+      },
+    },
+    x: {
+      grid: {
+        display: true,
+      },
+      ticks: {
+        font: {
+          family: "Lato-Regular",
+          size: 12,
+          lineHeight: 1.333,
+        },
+      },
+    },
+  },
+  responsive: true,
+  options: {
+    responsive: true,
+    maintainAspectRatio: true,
+  },
+  plugins: {
+    legend: {
+      position: "bottom",
+      display: true,
+      labels: {
+        font: {
+          family: "Lato-Regular",
+          size: 14,
+          lineHeight: 1.429,
+        },
+      },
+    },
+    datalabels: {
+      anchor: "end",
+      align: "end",
+    },
+  },
+};
+
+class LineChart extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      trigger: "",
+    };
+  }
+
+  /**
+   * Function to update the chart visualization
+   */
+  updateLineVisuals = () => {
+    this.setState({
+      trigger: true,
+    });
+    this.props.pathName.history.push({
+      pathName: "/dashboards",
+      state: { trigger: this.state.trigger },
+    });
+  };
+
+  manupulateData(chartData) {
+    var tempdata = {
+      labels: [],
+      datasets: [],
+    };
+
+    chartData.forEach((d, i) => {
+      let colors = linePalette("cb-BasePalette2", chartData.length).map(
+        function (hex) {
+          return "#" + hex;
+        }
+      );
+      let tempObj = {
+        label: "",
+        borderColor: colors[i],
+        backgroundColor: colors[i],
+        fill: false,
+      };
+
+      let tempdataArr = [];
+      let tempdatalabel = [],
+        tempVal = "";
+      tempObj.label = d.headerName;
+      d.plots.forEach((d1, i) => {
+        tempVal = NFormatterFun(d1.value, d1.symbol, "Unit");
+        tempVal =
+          typeof tempVal == "string"
+            ? parseFloat(tempVal.replace(/,/g, ""))
+            : tempVal;
+        tempdataArr.push(d1.value);
+        if (d1.name.length > 20) {
+          tempdatalabel.push(d1.name.match(/.{1,20}\S+\s*/g));
+        } else {
+          tempdatalabel.push(d1.name);
+        }
+      });
+      tempObj.data = tempdataArr;
+      tempdata.labels = tempdatalabel;
+      tempdata.datasets.push(tempObj);
+    });
+    return tempdata;
+  }
+
+  render() {
+    let { chartData } = this.props;
+    let data = this.manupulateData(chartData);
+
+    /*
+     * Function to get the chart label title
+     */
+    const getLineLabelFilter = (elems) => {
+      if (localStorage.getItem("filterKey") && elems[0] !== undefined) {
+        let index = elems[0]._datasetIndex;
+        let selectedLabel = elems[0]._xScale.chart.data.datasets[index].label;
+        localStorage.setItem("label", selectedLabel);
+        this.updateLineVisuals();
+      } else {
+        // console.log("Out!");
+      }
+    };
+
+    if (data) {
+      return (
+        <Line
+          height={this.props.dimensions.height}
+          style={{ fill: "none" }}
+          data={data}
+          options={options}
+          plugins={[
+            {
+              beforeInit: (chart, options) => {
+                chart.legend.afterFit = () => {
+                  if (chart.legend.margins) {
+                    chart.legend.options.labels.padding = 20;
+                  }
+                };
+              },
+            },
+          ]}
+          getElementAtEvent={(elems) => getLineLabelFilter(elems)}
+        ></Line>
+      );
+    }
+    return <div>Loading...</div>;
+  }
+}
+
+export default LineChart;
diff --git a/src/components/charts/MetricVisual.js b/src/components/charts/MetricVisual.js
new file mode 100644
index 0000000000000000000000000000000000000000..404a19f49fa8da04eb92e014bbf3a9b9d36e06f5
--- /dev/null
+++ b/src/components/charts/MetricVisual.js
@@ -0,0 +1,37 @@
+import React from "react";
+
+/**
+ * Metric visual component
+ */
+
+class MetricVisual extends React.Component {
+  getData(chartData) {
+    return chartData;
+  }
+
+  render() {
+    let { chartData } = this.props;
+    let _data = this.getData(chartData);
+
+    if (_data) {
+      return (
+        <div className="">
+          {_data.map((value, index) => (
+            <div className="customLineHeight" key={index}>
+              <p className="metricTextColor">{value.headerName}</p>
+              {!value.isDecimal ? (
+                <p className="largeNum">{Math.round(value.headerValue)}</p>
+              ) : (
+                <p className="largeNum">{value.headerValue}</p>
+              )}
+              <p>&nbsp;</p>
+            </div>
+          ))}
+        </div>
+      );
+    }
+    return <div>Loading...</div>;
+  }
+}
+
+export default MetricVisual;
diff --git a/src/components/charts/MixedData.js b/src/components/charts/MixedData.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d3478cd95373005a888600e8eada5712602fd3c
--- /dev/null
+++ b/src/components/charts/MixedData.js
@@ -0,0 +1,148 @@
+import React from "react";
+import { Bar } from "react-chartjs-2";
+
+/**
+ * MixedData component
+ */
+
+const options = {
+  elements: {
+    point: {
+      radius: 0,
+    },
+    line: {
+      tension: 0,
+    },
+  },
+  scales: {
+    xAxes: [
+      {
+        gridLines: {
+          color: "rgba(0, 0, 0, 0)",
+          display: false,
+        },
+      },
+    ],
+    yAxes: [
+      {
+        gridLines: {
+          display: true,
+          drawBorder: false,
+        },
+      },
+      {
+        id: "left-y-axis",
+        display: true,
+        type: "linear",
+        position: "left",
+      },
+      {
+        id: "right-y-axis",
+        display: true,
+        type: "linear",
+        position: "right",
+      },
+    ],
+  },
+  responsive: true,
+  options: {
+    responsive: true,
+    maintainAspectRatio: true,
+  },
+  plugins: {
+    legend: {
+      position: "bottom",
+    },
+  },
+};
+
+class MixedData extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      data: null,
+    };
+  }
+  getData(chartData) {
+    var tempData = {
+      labels: [],
+      datasets: [],
+    };
+    var tempdataSet = {
+      label: "",
+      type: "line",
+      borderColor: "#F3457E",
+      backgroundColor: "transparent",
+      yAxisID: "right-y-axis",
+      data: [],
+      dataSymbol: [],
+      order: 1,
+    };
+    var tempdataSetTwo = {
+      label: "",
+      type: "bar",
+      backgroundColor: "#7B47A4",
+      yAxisID: "left-y-axis",
+      data: [],
+      dataSymbol: [],
+      order: 2,
+    };
+
+    for (var i = 0; i < chartData.length; i++) {
+      // Bar Data
+      if (i === 0) {
+        tempdataSetTwo.label = chartData[i].headerName;
+        for (var l = 0; l < chartData[i].plots.length; l++) {
+          tempData.labels.push(chartData[i].plots[l]["name"]);
+          tempdataSetTwo.data.push(chartData[i].plots[l]["value"]);
+          tempdataSetTwo.dataSymbol.push([
+            chartData[i].plots[l]["symbol"],
+            "Unit",
+          ]);
+        }
+      }
+      // Line Data
+      if (i === 1) {
+        tempdataSet.label = chartData[i].headerName;
+        for (var j = 0; j < chartData[i].plots.length; j++) {
+          tempdataSet.data.push(chartData[i].plots[j]["value"]);
+          tempdataSet.dataSymbol.push([
+            chartData[i].plots[j]["symbol"],
+            "Unit",
+          ]);
+        }
+      }
+    }
+
+    tempData.datasets.push(tempdataSetTwo);
+    tempData.datasets.push(tempdataSet);
+    return tempData;
+  }
+
+  render() {
+    let { chartData } = this.props;
+    let _data = this.getData(chartData);
+    if (_data) {
+      return (
+        <Bar
+          data={_data}
+          plugins={[
+            {
+              beforeInit: (chart, options) => {
+                chart.legend.afterFit = () => {
+                  if (chart.legend.margins) {
+                    chart.legend.options.labels.padding = 20;
+                  }
+                };
+              },
+            },
+          ]}
+          options={options}
+        />
+      );
+    }
+    return <div>Loading...</div>;
+  }
+}
+
+export default MixedData;
diff --git a/src/components/charts/NFormatterFun.js b/src/components/charts/NFormatterFun.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c168cfed4aa0b989d634fda8064e27fe5624024
--- /dev/null
+++ b/src/components/charts/NFormatterFun.js
@@ -0,0 +1,79 @@
+export default function NFormatterTest(
+  value,
+  type,
+  symbol,
+  commaSeparated = false
+) {
+  var SI_SYMBOL = ["Unit", "Lac", "Cr"];
+  const Rformatter = new Intl.NumberFormat("en-IN", {
+    // maximumFractionDigits:0,
+    useGrouping: true,
+    // currencyDisplay : Intl.NumberFormatOptions
+    //style: 'currency',
+    currency: "INR",
+  });
+  // return value;
+  switch (type) {
+    case "amount":
+    case "Amount":
+      switch (symbol) {
+        case SI_SYMBOL[1]:
+          return (
+            `${Rformatter.format((value / 100000).toFixed(2))}` ||
+            `${Rformatter.format(0)}`
+          );
+
+        case SI_SYMBOL[2]:
+          return (
+            `${Rformatter.format((value / 10000000).toFixed(2))}` ||
+            `${Rformatter.format(0)}`
+          );
+
+        case SI_SYMBOL[0]:
+          if (value <= 9999999) {
+            return `${Rformatter.format(value || 0)}`;
+          } else {
+            if (!commaSeparated) {
+              return value;
+              // let nvalue = Rformatter.format((value).toFixed(2) || 0).replace('₹ ', '');
+              // var right = nvalue.substring(nvalue.length - 12, nvalue.length);
+              // var left = nvalue.substring(0, nvalue.length - 12).replace(',', '');
+              // let newVal = (left ? (left + ',') : '') + right;
+              // return parseFloat(newVal.replace(",,", ',').replace(',', ''));
+            } else {
+              let nvalue = Rformatter.format(value.toFixed(2) || 0).replace(
+                "₹ ",
+                ""
+              );
+              var right = nvalue.substring(nvalue.length - 12, nvalue.length);
+              var left = nvalue
+                .substring(0, nvalue.length - 12)
+                .replace(",", "");
+              let newVal = (left ? left + "," : "") + right;
+              return newVal.replace(",,", ",");
+            }
+          }
+
+        default:
+          return parseFloat(`${Rformatter.format(value || 0)}`);
+      }
+    case "number":
+    case "Number":
+      if (!commaSeparated) {
+        return parseInt(value);
+      }
+      const Nformatter = new Intl.NumberFormat("en-IN");
+      return Nformatter.format(Math.round(value));
+    case "percentage":
+    case "Percentage":
+      const Pformatter = new Intl.NumberFormat("en-IN", {
+        maximumSignificantDigits: 3,
+      });
+      return `${Pformatter.format(value)} %`;
+    case "text":
+    case "Text":
+      return value;
+    default:
+      return value;
+  }
+}
diff --git a/src/components/charts/PieChart.js b/src/components/charts/PieChart.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c75d715be584b219405fc7f6705fd87aaf06800
--- /dev/null
+++ b/src/components/charts/PieChart.js
@@ -0,0 +1,144 @@
+import React from "react";
+import { Pie } from "react-chartjs-2";
+import _ from "lodash";
+import piePalette from "./palette";
+
+/**
+ * PieChart component
+ */
+
+const pieChartOptions = {
+  options: {
+    responsive: true,
+    maintainAspectRatio: false,
+  },
+  plugins: {
+    legend: {
+      position: "bottom",
+      display: true,
+      labels: {
+        font: {
+          family: "Lato-Regular",
+          size: 14,
+          lineHeight: 1.429,
+        },
+      },
+    },
+    datalabels: {
+      anchor: "end",
+      align: "end",
+    },
+  },
+};
+
+class PieChart extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      data: null,
+      trigger: "",
+    };
+  }
+
+  /**
+   * Function to update the chart visualization
+   */
+  updatePieVisuals = () => {
+    this.setState({
+      trigger: true,
+    });
+    this.props.pathName.history.push({
+      pathName: "/dashboards",
+      state: { trigger: this.state.trigger },
+    });
+    setTimeout(() => {
+      this.props.pathName.history.push({
+        pathName: "/dashboards",
+        state: { trigger: this.state.trigger },
+      });
+    }, 500);
+  };
+
+  getData(chartData) {
+    var pieChartTempData = {
+      labels: [],
+      datasets: [],
+    };
+    var pieChartTempDataSet = {
+      label: "",
+      data: [],
+      dataSymbol: [],
+    };
+
+    _.map(chartData, function (k, v) {
+      var plots = k["plots"];
+      for (var i = 0; i < plots.length; i++) {
+        pieChartTempData.labels.push(plots[i]["name"]);
+        pieChartTempDataSet.data.push(plots[i]["value"]);
+        pieChartTempDataSet.dataSymbol.push([plots[i]["symbol"], "Unit"]);
+      }
+    });
+
+    pieChartTempDataSet.backgroundColor = piePalette(
+      "cb-BasePalette",
+      pieChartTempDataSet.data.length
+    ).map(function (hex) {
+      return "#" + hex;
+    });
+    pieChartTempDataSet.borderColor = piePalette(
+      "cb-BasePalette",
+      pieChartTempDataSet.data.length
+    ).map(function (hex) {
+      return "#" + hex;
+    });
+    pieChartTempData.datasets.push(pieChartTempDataSet);
+    return pieChartTempData;
+  }
+
+  render() {
+    let { chartData } = this.props;
+    let _data = this.getData(chartData);
+
+    /*
+     * Function to get the chart label title
+     */
+    const getPieLabelFilter = (elems) => {
+      if (localStorage.getItem("filterKey") && elems[0] !== undefined) {
+        let index = elems[0]._index;
+        let selectedLabel = {
+          labels: [],
+        };
+        selectedLabel.labels.push(elems[0]._chart.data.labels[index]);
+        localStorage.setItem("label", selectedLabel.labels);
+        this.updatePieVisuals();
+      } else {
+        // console.log("Out!");
+      }
+    };
+
+    if (_data) {
+      return (
+        <Pie
+          height={this.props.dimensions.height}
+          data={_data}
+          options={pieChartOptions}
+          plugins={[
+            {
+              beforeInit: (chart, options) => {
+                chart.legend.afterFit = () => {
+                  if (chart.legend.margins) {
+                    chart.legend.options.labels.padding = 15;
+                  }
+                };
+              },
+            },
+          ]}
+          getElementAtEvent={(elems) => getPieLabelFilter(elems)}
+        />
+      );
+    }
+    return <div>Loading...</div>;
+  }
+}
+
+export default PieChart;
diff --git a/src/components/charts/WidgetNavBar.js b/src/components/charts/WidgetNavBar.js
new file mode 100644
index 0000000000000000000000000000000000000000..c30ef8b18b804849f5333d4fcce1b55cd833d04c
--- /dev/null
+++ b/src/components/charts/WidgetNavBar.js
@@ -0,0 +1,199 @@
+import React, { Component } from "react";
+import * as moment from "moment";
+import _ from "lodash";
+import "file-saver";
+// import domtoimage from "dom-to-image";
+import { ChartService } from "../../services";
+
+/**
+ * Widget Navbar Component
+ * Holds all the widgets and drill throught filter labels
+ */
+
+class WidgetNavBar extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      showDateFilter: false,
+      showCustomDateFilter: false,
+      dashboardConfigData: [],
+      selectedDate: moment().format("DD MMM YY"),
+      selectedFilter: "Today",
+      rangeSelected: "",
+      startDate: "",
+      endDate: "",
+      trigger: "",
+      selectedTab: "",
+      tabsInitDataId: [],
+      chartsGData: {},
+      widgetData: [],
+      showOne: false,
+    };
+  }
+
+  componentDidMount() {
+    let thisMonthRange =
+      moment().startOf("month").format("DD MMM") +
+      " - " +
+      moment().endOf("month").format("DD MMM");
+    this.setState({
+      selectedFilter: "This month",
+      selectedDate: thisMonthRange,
+    });
+
+    ChartService.getDashboardConfig().then(
+      (response) => {
+        this.setState((prevState) => ({
+          ...prevState,
+          dashboardConfigData: response.responseData,
+        }));
+        if (!this.state.chartsGData.length) {
+          setTimeout(() => this.getWidgets(), 150);
+        }
+      },
+      (error) => {}
+    );
+  }
+
+  /**
+   * Function to get the chart data as per the dashboard selection
+   */
+  getChartData = (code) => {
+    let startRange = moment().startOf("month");
+    let endRange = moment().endOf("month");
+    startRange = Number(startRange);
+    endRange = Number(endRange);
+    let thisMonth = { startDate: startRange, endDate: endRange };
+
+    let payload = {
+      RequestInfo: {
+        authToken: "null",
+      },
+      headers: {
+        tenantId: "null",
+      },
+      aggregationRequestDto: {
+        dashboardId: "home",
+        visualizationType: "METRIC",
+        visualizationCode: code,
+        queryType: "",
+        filters: {},
+        moduleLevel: "",
+        aggregationFactors: null,
+        requestDate: thisMonth,
+      },
+    };
+
+    ChartService.getChartData(payload).then(
+      (response) => {
+        this.setState(
+          (prevState) => ({
+            ...prevState,
+            chartsGData: {
+              ...prevState.chartsGData,
+              [code]: response.responseData,
+            },
+          }),
+          () => {
+            let chartDetails = JSON.stringify(this.state.chartsGData);
+            chartDetails = JSON.parse(chartDetails);
+            chartDetails = _.chain(chartDetails).map();
+            chartDetails = JSON.stringify(chartDetails);
+            chartDetails = JSON.parse(chartDetails);
+            let chartData = [];
+            chartDetails.map((details) => chartData.push(details.data[0]));
+            this.setState({
+              widgetData: [...chartData],
+            });
+          }
+        );
+      },
+      (error) => {}
+    );
+  };
+
+  /**
+   * Function to get the widgets data as per the dashboard selection
+   */
+  getWidgets = () => {
+    let data = this.state.dashboardConfigData;
+    let dashboardWidget = _.chain(data)
+      .first()
+      .get("widgetCharts")
+      .groupBy("name")
+      .value();
+    let widgetArray = _.chain(dashboardWidget).map();
+    widgetArray = JSON.stringify(widgetArray);
+    widgetArray = JSON.parse(widgetArray);
+    let id = [];
+    widgetArray.map((code) => id.push(code[0].id));
+    id.map((code) => this.getChartData(code));
+  };
+
+  filterImage = (node) => {
+    return (
+      node.id !== "downloadDashIcon" &&
+      node.id !== "dropdownMenuButton" &&
+      node.id !== "zoomIn" &&
+      node.id !== "zoomOut" &&
+      node.id !== "zoomInBtn" &&
+      node.id !== "zoomOutBtn"
+    );
+  };
+
+  /**
+   * Function to update the chart visualization
+   */
+  updateVisuals = () => {
+    this.setState({
+      trigger: true,
+    });
+    this.props.pathName.history.push({
+      pathName: "/dashboards",
+      state: { trigger: this.state.trigger },
+    });
+    setTimeout(() => {
+      this.props.pathName.history.push({
+        pathName: "/dashboards",
+        state: { trigger: this.state.trigger },
+      });
+    }, 500);
+  };
+
+  render() {
+    return (
+      <div className="mt-4">
+        <div
+          className={`row col-12 ${
+            this.state.widgetData && this.state.widgetData.length > 0
+              ? "mt-4"
+              : "mt-0"
+          }`}
+          id="widgets"
+        >
+          {this.state.widgetData.map((data, index) => (
+            <div
+              className="col-xs-12 col-sm-12 col-md-4 col-lg-4 col-xl-2 pb-3 pb-xs-3 pb-sm-3 pb-md-3 pb-lg-0 pb-xl-0 widget_card_one px-4"
+              key={data.headerName}
+            >
+              {(data.headerName || data.headerValue) && (
+                <div className={`me-2 pt-3 widget-box-${index + 1}`}>
+                  <h2 className="mt-3">
+                    {!data.isDecimal ? (
+                      <p>{Math.round(data.headerValue)}</p>
+                    ) : (
+                      <p>{data.headerValue}</p>
+                    )}
+                  </h2>
+                  <label className="pb-3">{data.headerName}</label>
+                </div>
+              )}
+            </div>
+          ))}
+        </div>
+      </div>
+    );
+  }
+}
+
+export default WidgetNavBar;
diff --git a/src/components/charts/palette.js b/src/components/charts/palette.js
new file mode 100644
index 0000000000000000000000000000000000000000..a3a8659f006edee0b77d753fd47aac84c167e60d
--- /dev/null
+++ b/src/components/charts/palette.js
@@ -0,0 +1,1568 @@
+/* eslint-disable no-unused-expressions */
+/** @license
+ *
+ *     Colour Palette Generator script.
+ *     Copyright (c) 2014 Google Inc.
+ *
+ *     Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *     not use this file except in compliance with the License.  You may
+ *     obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *     Unless required by applicable law or agreed to in writing, software
+ *     distributed under the License is distributed on an "AS IS" BASIS,
+ *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *     implied.  See the License for the specific language governing
+ *     permissions and limitations under the License.
+ *
+ * Furthermore, ColorBrewer colour schemes are covered by the following:
+ *
+ *     Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and
+ *                        The Pennsylvania State University.
+ *
+ *     Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *     not use this file except in compliance with the License. You may obtain
+ *     a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *     Unless required by applicable law or agreed to in writing, software
+ *     distributed under the License is distributed on an "AS IS" BASIS,
+ *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *     implied. See the License for the specific language governing
+ *     permissions and limitations under the License.
+ *
+ *     Redistribution and use in source and binary forms, with or without
+ *     modification, are permitted provided that the following conditions are
+ *     met:
+ *
+ *     1. Redistributions as source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *     2. The end-user documentation included with the redistribution, if any,
+ *     must include the following acknowledgment: "This product includes color
+ *     specifications and designs developed by Cynthia Brewer
+ *     (http://colorbrewer.org/)." Alternately, this acknowledgment may appear
+ *     in the software itself, if and wherever such third-party
+ *     acknowledgments normally appear.
+ *
+ *     4. The name "ColorBrewer" must not be used to endorse or promote products
+ *     derived from this software without prior written permission. For written
+ *     permission, please contact Cynthia Brewer at cbrewer@psu.edu.
+ *
+ *     5. Products derived from this software may not be called "ColorBrewer",
+ *     nor may "ColorBrewer" appear in their name, without prior written
+ *     permission of Cynthia Brewer.
+ *
+ * Furthermore, Solarized colour schemes are covered by the following:
+ *
+ *     Copyright (c) 2011 Ethan Schoonover
+ *
+ *     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.
+ */
+
+//  'use strict';
+
+ var palette = (function() {
+ 
+   var proto = Array.prototype;
+   var slice = function(arr, opt_begin, opt_end) {
+     return proto.slice.apply(arr, proto.slice.call(arguments, 1));
+   };
+ 
+  //  var extend = function(arr, arr2) {
+  //    return proto.push.apply(arr, arr2);
+  //  };
+ 
+   var function_type = typeof function() {};
+ 
+   var INF = 1000000000;  // As far as we're concerned, that's infinity. ;)
+ 
+ 
+   /**
+    * Generate a colour palette from given scheme.
+    *
+    * If scheme argument is not a function it is passed to palettes.listSchemes
+    * function (along with the number argument).  This may result in an array
+    * of more than one available scheme.  If that is the case, scheme at
+    * opt_index position is taken.
+    *
+    * This allows using different palettes for different data without having to
+    * name the schemes specifically, for example:
+    *
+    *     palette_for_foo = palette('sequential', 10, 0);
+    *     palette_for_bar = palette('sequential', 10, 1);
+    *     palette_for_baz = palette('sequential', 10, 2);
+    *
+    * @param {!palette.SchemeType|string|palette.Palette} scheme Scheme to
+    *     generate palette for.  Either a function constructed with
+    *     palette.Scheme object, or anything that palette.listSchemes accepts
+    *     as name argument.
+    * @param {number} number Number of colours to return.  If negative, absolute
+    *     value is taken and colours will be returned in reverse order.
+    * @param {number=} opt_index If scheme is a name of a group or an array and
+    *     results in more than one scheme, index of the scheme to use.  The
+    *     index wraps around.
+    * @param {...*} varargs Additional arguments to pass to palette or colour
+    *     generator (if the chosen scheme uses those).
+    * @return {Array<string>} Array of abs(number) 'RRGGBB' strings or null if
+    *     no matching scheme was found.
+    */
+   var palette = function(scheme, number, opt_index, varargs) {
+     number |= 0;
+     if (number === 0) {
+       return [];
+     }
+ 
+     if (typeof scheme !== function_type) {
+       var arr = palette.listSchemes(
+           /** @type {string|palette.Palette} */ (scheme), number);
+       if (!arr.length) {
+         return null;
+       }
+       scheme = arr[(opt_index || 0) % arr.length];
+     }
+ 
+     var args = slice(arguments, 2);
+     args[0] = number;
+     return scheme.apply(scheme, args);
+   };
+ 
+ 
+   /**
+    * Returns a callable colour scheme object.
+    *
+    * Just after being created, the scheme has no colour palettes and no way of
+    * generating any, thus generate method will return null.  To turn scheme
+    * into a useful object, addPalette, addPalettes or setColorFunction methods
+    * need to be used.
+    *
+    * To generate a colour palette with given number colours using function
+    * returned by this method, just call it with desired number of colours.
+    *
+    * Since this function *returns* a callable object, it must *not* be used
+    * with the new operator.
+    *
+    * @param {string} name Name of the scheme.
+    * @param {string|!Array<string>=} opt_groups A group name or list of
+    *     groups the scheme should be categorised under.  Three typical groups
+    *     to use are 'qualitative', 'sequential' and 'diverging', but any
+    *     groups may be created.
+    * @return {!palette.SchemeType} A colour palette generator function, which
+    *     in addition has methods and properties like a regular object.  Think
+    *     of it as a callable object.
+    */
+   palette.Scheme = function(name, opt_groups) {
+     /**
+      * A map from a number to a colour palettes with given number of colours.
+      * @type {!Object<number, palette.Palette>}
+      */
+     var palettes = {};
+ 
+     /**
+      * The biggest palette in palettes map.
+      * @type {number}
+      */
+     var palettes_max = 0;
+ 
+     /**
+      * The smallest palette in palettes map.
+      * @type {number}
+      */
+     var palettes_min = INF;
+ 
+     var makeGenerator = function() {
+       if (arguments.length <= 1) {
+         return self.color_func.bind(self);
+       } else {
+         var args = slice(arguments);
+         return function(x) {
+           args[0] = x;
+           return self.color_func.apply(self, args);
+         };
+       }
+     };
+ 
+     /**
+      * Generate a colour palette from the scheme.
+      *
+      * If there was a palette added with addPalette (or addPalettes) with
+      * enough colours, that palette will be used.  Otherwise, if colour
+      * function has been set using setColorFunction method, that function will
+      * be used to generate the palette.  Otherwise null is returned.
+      *
+      * @param {number} number Number of colours to return.  If negative,
+      *     absolute value is taken and colours will be returned in reverse
+      *     order.
+      * @param {...*} varargs Additional arguments to pass to palette or colour
+      *     generator (if the chosen scheme uses those).
+      */
+     var self = function(number, varargs) {
+       number |= 0;
+       if (!number) {
+         return [];
+       }
+ 
+       var _number = number;
+       number = Math.abs(number);
+ 
+       if (number <= palettes_max) {
+         for (var i = Math.max(number, palettes_min); !(i in palettes); ++i) {
+           /* nop */
+         }
+         var colors = palettes[i];
+         if (i > number) {
+           var take_head =
+               'shrinking_takes_head' in colors ?
+               colors.shrinking_takes_head : self.shrinking_takes_head;
+           if (take_head) {
+             colors = colors.slice(0, number);
+             i = number;
+           } else {
+             return palette.generate(
+                 function(x) { return colors[Math.round(x)]; },
+                 _number, 0, colors.length - 1);
+           }
+         }
+         colors = colors.slice();
+         if (_number < 0) {
+           colors.reverse();
+         }
+         return colors;
+ 
+       } else if (self.color_func) {
+         return palette.generate(makeGenerator.apply(self, arguments),
+                                 _number, 0, 1, self.color_func_cyclic);
+ 
+       } else {
+         return null;
+       }
+     };
+ 
+     /**
+      * The name of the palette.
+      * @type {string}
+      */
+     self.scheme_name = name;
+ 
+     /**
+      * A list of groups the palette belongs to.
+      * @type {!Array<string>}
+      */
+     self.groups = opt_groups ?
+       typeof opt_groups === 'string' ? [opt_groups] : opt_groups : [];
+ 
+     /**
+      * The biggest palette this scheme can generate.
+      * @type {number}
+      */
+     self.max = 0;
+ 
+     /**
+      * The biggest palette this scheme can generate that is colour-blind
+      * friendly.
+      * @type {number}
+      */
+     self.cbf_max = INF;
+ 
+ 
+     /**
+      * Adds a colour palette to the colour scheme.
+      *
+      * @param {palette.Palette} palette An array of 'RRGGBB' strings
+      *     representing the palette to add.
+      * @param {boolean=} opt_is_cbf Whether the palette is colourblind friendly.
+      */
+     self.addPalette = function(palette, opt_is_cbf) {
+       var len = palette.length;
+       if (len) {
+         palettes[len] = palette;
+         palettes_min = Math.min(palettes_min, len);
+         palettes_max = Math.max(palettes_max, len);
+         self.max = Math.max(self.max, len);
+         if (!opt_is_cbf && len !== 1) {
+           self.cbf_max = Math.min(self.cbf_max, len - 1);
+         }
+       }
+     };
+ 
+     /**
+      * Adds number of colour palettes to the colour scheme.
+      *
+      * @param {palette.PalettesList} palettes A map or an array of colour
+      *     palettes to add.  If map, i.e.  object, is used, properties should
+      *     use integer property names.
+      * @param {number=} opt_max Size of the biggest palette in palettes set.
+      *     If not set, palettes must have a length property which will be used.
+      * @param {number=} opt_cbf_max Size of the biggest palette which is still
+      *     colourblind friendly.  1 by default.
+      */
+     self.addPalettes = function(palettes, opt_max, opt_cbf_max) {
+       opt_max = opt_max || palettes.length;
+       for (var i = 0; i < opt_max; ++i) {
+         if (i in palettes) {
+           self.addPalette(palettes[i], true);
+         }
+       }
+       self.cbf_max = Math.min(self.cbf_max, opt_cbf_max || 1);
+     };
+ 
+     /**
+      * Enable shrinking palettes taking head of the list of colours.
+      *
+      * When user requests n-colour palette but the smallest palette added with
+      * addPalette (or addPalettes) is m-colour one (where n < m), n colours
+      * across the palette will be returned.  For example:
+      *     var ex = palette.Scheme('ex');
+      *     ex.addPalette(['000000', 'bcbcbc', 'ffffff']);
+      *     var pal = ex(2);
+      *     // pal == ['000000', 'ffffff']
+      *
+      * This works for palettes where the distance between colours is
+      * correlated to distance in the palette array, which is true in gradients
+      * such as the one above.
+      *
+      * To turn this feature off shrinkByTakingHead can be set to true either
+      * for all palettes in the scheme (if opt_idx is not given) or for palette
+      * with given number of colours only.  In general, setting the option for
+      * given palette overwrites whatever has been set for the scheme.  The
+      * default, as described above, is false.
+      *
+      * Alternatively, the feature can be enabled by setting shrinking_takes_head
+      * property for the palette Array or the scheme object.
+      *
+      * For example, all of the below give equivalent results:
+      *     var pal = ['ff0000', '00ff00', '0000ff'];
+      *
+      *     var ex = palette.Scheme('ex');
+      *     ex.addPalette(pal);               // ex(2) == ['ff0000', '0000ff']
+      *     ex.shrinkByTakingHead(true);      // ex(2) == ['ff0000', '00ff00']
+      *
+      *     ex = palette.Scheme('ex');
+      *     ex.addPalette(pal);               // ex(2) == ['ff0000', '0000ff']
+      *     ex.shrinkByTakingHead(true, 3);   // ex(2) == ['ff0000', '00ff00']
+      *
+      *     ex = palette.Scheme('ex');
+      *     ex.addPalette(pal);
+      *     ex.addPalette(pal);               // ex(2) == ['ff0000', '0000ff']
+      *     pal.shrinking_takes_head = true;  // ex(2) == ['ff0000', '00ff00']
+      *
+      * @param {boolean} enabled Whether to enable or disable the “shrinking
+      *     takes head” feature.  It is disabled by default.
+      * @param {number=} opt_idx If given, the “shrinking takes head” option
+      *     for palette with given number of colours is set.  If such palette
+      *     does not exist, nothing happens.
+      */
+     self.shrinkByTakingHead = function(enabled, opt_idx) {
+       if (opt_idx !== void(0)) {
+         if (opt_idx in palettes) {
+           palettes[opt_idx].shrinking_takes_head = !!enabled;
+         }
+       } else {
+         self.shrinking_takes_head = !!enabled;
+       }
+     };
+ 
+     /**
+      * Sets a colour generation function of the colour scheme.
+      *
+      * The function must accept a singe number argument whose value can be from
+      * 0.0 to 1.0, and return a colour as an 'RRGGBB' string.  This function
+      * will be used when generating palettes, i.e. if 11-colour palette is
+      * requested, this function will be called with arguments 0.0, 0.1, …, 1.0.
+      *
+      * If the palette generated by the function is colourblind friendly,
+      * opt_is_cbf should be set to true.
+      *
+      * In some cases, it is not desirable to reach 1.0 when generating
+      * a palette.  This happens for hue-rainbows where the 0–1 range corresponds
+      * to a 0°–360° range in hues, and since hue at 0° is the same as at 360°,
+      * it's desired to stop short the end of the range when generating
+      * a palette.  To accomplish this, opt_cyclic should be set to true.
+      *
+      * @param {palette.ColorFunction} func A colour generator function.
+      * @param {boolean=} opt_is_cbf Whether palette generate with the function
+      *     is colour-blind friendly.
+      * @param {boolean=} opt_cyclic Whether colour at 0.0 is the same as the
+      *     one at 1.0.
+      */
+     self.setColorFunction = function(func, opt_is_cbf, opt_cyclic) {
+       self.color_func = func;
+       self.color_func_cyclic = !!opt_cyclic;
+       self.max = INF;
+       if (!opt_is_cbf && self.cbf_max === INF) {
+         self.cbf_max = 1;
+       }
+     };
+ 
+     self.color = function(x, varargs) {
+       if (self.color_func) {
+         return self.color_func.apply(this, arguments);
+       } else {
+         return null;
+       }
+     };
+ 
+     return self;
+   };
+ 
+ 
+   /**
+    * Creates a new palette.Scheme and initialises it by calling addPalettes
+    * method with the rest of the arguments.
+    *
+    * @param {string} name Name of the scheme.
+    * @param {string|!Array<string>} groups A group name or list of group
+    *     names the scheme belongs to.
+    * @param {!Object<number, palette.Palette>|!Array<palette.Palette>}
+    *     palettes A map or an array of colour palettes to add.  If map, i.e.
+    *     object, is used, properties should use integer property names.
+    * @param {number=} opt_max Size of the biggest palette in palettes set.
+    *     If not set, palettes must have a length property which will be used.
+    * @param {number=} opt_cbf_max Size of the biggest palette which is still
+    *     colourblind friendly.  1 by default.
+    * @return {!palette.SchemeType} A colour palette generator function, which
+    *     in addition has methods and properties like a regular object.  Think
+    *     of it as a callable object.
+    */
+   palette.Scheme.fromPalettes = function(name, groups,
+                                          palettes, opt_max, opt_cbf_max) {
+     var scheme = palette.Scheme(name, groups);
+     scheme.addPalettes.apply(scheme, slice(arguments, 2));
+     return scheme;
+   };
+ 
+ 
+   /**
+    * Creates a new palette.Scheme and initialises it by calling
+    * setColorFunction method with the rest of the arguments.
+    *
+    * @param {string} name Name of the scheme.
+    * @param {string|!Array<string>} groups A group name or list of group
+    *     names the scheme belongs to.
+    * @param {palette.ColorFunction} func A colour generator function.
+    * @param {boolean=} opt_is_cbf Whether palette generate with the function
+    *     is colour-blind friendly.
+    * @param {boolean=} opt_cyclic Whether colour at 0.0 is the same as the
+    *     one at 1.0.
+    * @return {!palette.SchemeType} A colour palette generator function, which
+    *     in addition has methods and properties like a regular object.  Think
+    *     of it as a callable object.
+    */
+   palette.Scheme.withColorFunction = function(name, groups,
+                                               func, opt_is_cbf, opt_cyclic) {
+     var scheme = palette.Scheme(name, groups);
+     scheme.setColorFunction.apply(scheme, slice(arguments, 2));
+     return scheme;
+   };
+ 
+ 
+   /**
+    * A map of registered schemes.  Maps a scheme or group name to a list of
+    * scheme objects.  Property name is either 'n-<name>' for single scheme
+    * names or 'g-<name>' for scheme group names.
+    *
+    * @type {!Object<string, !Array<!Object>>}
+    */
+   var registered_schemes = {};
+ 
+ 
+   /**
+    * Registers a new colour scheme.
+    *
+    * @param {!palette.SchemeType} scheme The scheme to add.
+    */
+   palette.register = function(scheme) {
+     registered_schemes['n-' + scheme.scheme_name] = [scheme];
+     scheme.groups.forEach(function(g) {
+       (registered_schemes['g-' + g] =
+        registered_schemes['g-' + g] || []).push(scheme);
+     });
+     (registered_schemes['g-all'] =
+        registered_schemes['g-all'] || []).push(scheme);
+   };
+ 
+ 
+   /**
+    * List all schemes that match given name and number of colours.
+    *
+    * name argument can be either a string or an array of strings.  In the
+    * former case, the function acts as if the argument was an array with name
+    * as a single argument (i.e. “palette.listSchemes('foo')” is exactly the same
+    * as “palette.listSchemes(['foo'])”).
+    *
+    * Each name can be either name of a palette (e.g. 'tol-sq' for Paul Tol's
+    * sequential palette), or a name of a group (e.g. 'sequential' for all
+    * sequential palettes).  Name can therefore map to a single scheme or
+    * several schemes.
+    *
+    * Furthermore, name can be suffixed with '-cbf' to indicate that only
+    * schemes that are colourblind friendly should be returned.  For example,
+    * 'rainbow' returns a HSV rainbow scheme, but because it is not colourblind
+    * friendly, 'rainbow-cbf' returns no schemes.
+    *
+    * Some schemes may produce colourblind friendly palettes for some number of
+    * colours.  For example ColorBrewer's Dark2 scheme is colourblind friendly
+    * if no more than 3 colours are generated.  If opt_number is not specified,
+    * 'qualitative-cbf' will include 'cb-Dark2' but if opt_number is given as,
+    * say, 5 it won't.
+    *
+    * Name can also be 'all' which will return all registered schemes.
+    * Naturally, 'all-cbf' will return all colourblind friendly schemes.
+    *
+    * Schemes are added to the library using palette.register.  Schemes are
+    * created using palette.Scheme function.  By default, the following schemes
+    * are available:
+    *
+    *     Name            Description
+    *     --------------  -----------------------------------------------------
+    *     tol             Paul Tol's qualitative scheme, cbf, max 12 colours.
+    *     tol-dv          Paul Tol's diverging scheme, cbf.
+    *     tol-sq          Paul Tol's sequential scheme, cbf.
+    *     tol-rainbow     Paul Tol's qualitative scheme, cbf.
+    *
+    *     rainbow         A rainbow palette.
+    *
+    *     cb-YlGn         ColorBrewer sequential schemes.
+    *     cb-YlGnBu
+    *     cb-GnBu
+    *     cb-BuGn
+    *     cb-PuBuGn
+    *     cb-PuBu
+    *     cb-BuPu
+    *     cb-RdPu
+    *     cb-PuRd
+    *     cb-OrRd
+    *     cb-YlOrRd
+    *     cb-YlOrBr
+    *     cb-Purples
+    *     cb-Blues
+    *     cb-Greens
+    *     cb-Oranges
+    *     cb-Reds
+    *     cb-Greys
+    *
+    *     cb-PuOr         ColorBrewer diverging schemes.
+    *     cb-BrBG
+    *     cb-PRGn
+    *     cb-PiYG
+    *     cb-RdBu
+    *     cb-RdGy
+    *     cb-RdYlBu
+    *     cb-Spectral
+    *     cb-RdYlGn
+    *
+    *     cb-Accent       ColorBrewer qualitative schemes.
+    *     cb-Dark2
+    *     cb-Paired
+    *     cb-Pastel1
+    *     cb-Pastel2
+    *     cb-Set1
+    *     cb-Set2
+    *     cb-Set3
+    *
+    *     sol-base        Solarized base colours.
+    *     sol-accent      Solarized accent colours.
+    *
+    * The following groups are also available by default:
+    *
+    *     Name            Description
+    *     --------------  -----------------------------------------------------
+    *     all             All registered schemes.
+    *     sequential      All sequential schemes.
+    *     diverging       All diverging schemes.
+    *     qualitative     All qualitative schemes.
+    *     cb-sequential   All ColorBrewer sequential schemes.
+    *     cb-diverging    All ColorBrewer diverging schemes.
+    *     cb-qualitative  All ColorBrewer qualitative schemes.
+    *
+    * You can read more about Paul Tol's palettes at http://www.sron.nl/~pault/.
+    * You can read more about ColorBrewer at http://colorbrewer2.org.
+    *
+    * @param {string|!Array<string>} name A name of a colour scheme, of
+    *     a group of colour schemes, or an array of any of those.
+    * @param {number=} opt_number When requesting only colourblind friendly
+    *     schemes, number of colours the scheme must provide generating such
+    *     that the palette is still colourblind friendly.  2 by default.
+    * @return {!Array<!palette.SchemeType>} An array of colour scheme objects
+    *     matching the criteria.  Sorted by scheme name.
+    */
+   palette.listSchemes = function(name, opt_number) {
+     if (!opt_number) {
+       opt_number = 2;
+     } else if (opt_number < 0) {
+       opt_number = -opt_number;
+     }
+ 
+     var ret = [];
+     (typeof name === 'string' ? [name] : name).forEach(function(n) {
+       var cbf = n.substring(n.length - 4) === '-cbf';
+       if (cbf) {
+         n = n.substring(0, n.length - 4);
+       }
+       var schemes =
+           registered_schemes['g-' + n] ||
+           registered_schemes['n-' + n] ||
+           [];
+       for (var i = 0, scheme; (scheme = schemes[i]); ++i) {
+         if ((cbf ? scheme.cbf : scheme.max) >= opt_number) {
+           ret.push(scheme);
+         }
+       }
+     });
+ 
+     ret.sort(function(a, b) {
+       return a.scheme_name >= b.scheme_name ?
+         a.scheme_name > b.scheme_name ? 1 : 0 : -1;
+     });
+     return ret;
+   };
+ 
+ 
+   /**
+    * Generates a palette using given colour generating function.
+    *
+    * The color_func callback must accept a singe number argument whose value
+    * can vary from 0.0 to 1.0 (or in general from opt_start to opt_end), and
+    * return a colour as an 'RRGGBB' string.  This function will be used when
+    * generating palettes, i.e. if 11-colour palette is requested, this
+    * function will be called with arguments 0.0, 0.1, …, 1.0.
+    *
+    * In some cases, it is not desirable to reach 1.0 when generating
+    * a palette.  This happens for hue-rainbows where the 0–1 range corresponds
+    * to a 0°–360° range in hues, and since hue at 0° is the same as at 360°,
+    * it's desired to stop short the end of the range when generating
+    * a palette.  To accomplish this, opt_cyclic should be set to true.
+    *
+    * opt_start and opt_end may be used to change the range the colour
+    * generation function is called with.  opt_end may be less than opt_start
+    * which will case to traverse the range in reverse.  Another way to reverse
+    * the palette is requesting negative number of colours.  The two methods do
+    * not always lead to the same results (especially if opt_cyclic is set).
+    *
+    * @param {palette.ColorFunction} color_func A colours generating callback
+    *     function.
+    * @param {number} number Number of colours to generate in the palette.  If
+    *     number is negative, colours in the palette will be reversed.  If only
+    *     one colour is requested, colour at opt_start will be returned.
+    * @param {number=} opt_start Optional starting point for the palette
+    *     generation function.  Zero by default.
+    * @param {number=} opt_end Optional ending point for the palette generation
+    *     function.  One by default.
+    * @param {boolean=} opt_cyclic If true, function will assume colour at
+    *     point opt_start is the same as one at opt_end.
+    * @return {palette.Palette} An array of 'RRGGBB' colours.
+    */
+   palette.generate = function(color_func, number, opt_start, opt_end,
+                               opt_cyclic) {
+     if (Math.abs(number) < 1) {
+       return [];
+     }
+ 
+     opt_start = opt_start === void(0) ? 0 : opt_start;
+     opt_end = opt_end === void(0) ? 1 : opt_end;
+ 
+     if (Math.abs(number) < 2) {
+       return [color_func(opt_start)];
+     }
+ 
+     var i = Math.abs(number);
+     var x = opt_start;
+     var ret = [];
+     var step = (opt_end - opt_start) / (opt_cyclic ? i : (i - 1));
+ 
+     for (; --i >= 0; x += step) {
+       ret.push(color_func(x));
+     }
+     if (number < 0) {
+       ret.reverse();
+     }
+     return ret;
+   };
+ 
+ 
+   /**
+    * Clamps value to [0, 1] range.
+    * @param {number} v Number to limit value of.
+    * @return {number} If v is inside of [0, 1] range returns v, otherwise
+    *     returns 0 or 1 depending which side of the range v is closer to.
+    */
+   var clamp = function(v) {
+     return v > 0 ? (v < 1 ? v : 1) : 0;
+   };
+ 
+   /**
+    * Converts r, g, b triple into RRGGBB hex representation.
+    * @param {number} r Red value of the colour in the range [0, 1].
+    * @param {number} g Green value of the colour in the range [0, 1].
+    * @param {number} b Blue value of the colour in the range [0, 1].
+    * @return {string} A lower-case RRGGBB representation of the colour.
+    */
+   palette.rgbColor = function(r, g, b) {
+     return [r, g, b].map(function(v) {
+       v = Number(Math.round(clamp(v) * 255)).toString(16);
+       return v.length === 1 ? '0' + v : v;
+     }).join('');
+   };
+ 
+   /**
+    * Converts a linear r, g, b triple into RRGGBB hex representation.
+    * @param {number} r Linear red value of the colour in the range [0, 1].
+    * @param {number} g Linear green value of the colour in the range [0, 1].
+    * @param {number} b Linear blue value of the colour in the range [0, 1].
+    * @return {string} A lower-case RRGGBB representation of the colour.
+    */
+   palette.linearRgbColor = function(r, g, b) {
+     // http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html
+     return [r, g, b].map(function(v) {
+       v = clamp(v);
+       if (v <= 0.0031308) {
+         v = 12.92 * v;
+       } else {
+         v = 1.055 * Math.pow(v, 1 / 2.4) - 0.055;
+       }
+       v = Number(Math.round(v * 255)).toString(16);
+       return v.length === 1 ? '0' + v : v;
+     }).join('');
+   };
+ 
+   /**
+    * Converts an HSV colours to RRGGBB hex representation.
+    * @param {number} h Hue in the range [0, 1].
+    * @param {number=} opt_s Saturation in the range [0, 1].  One by default.
+    * @param {number=} opt_v Value in the range [0, 1].  One by default.
+    * @return {string} An RRGGBB representation of the colour.
+    */
+   palette.hsvColor = function(h, opt_s, opt_v) {
+     h *= 6;
+     var s = opt_s === void(0) ? 1 : clamp(opt_s);
+     var v = opt_v === void(0) ? 1 : clamp(opt_v);
+     var x = v * (1 - s * Math.abs(h % 2 - 1));
+     var m = v * (1 - s);
+     switch (Math.floor(h) % 6) {
+     case 0: return palette.rgbColor(v, x, m);
+     case 1: return palette.rgbColor(x, v, m);
+     case 2: return palette.rgbColor(m, v, x);
+     case 3: return palette.rgbColor(m, x, v);
+     case 4: return palette.rgbColor(x, m, v);
+     default: return palette.rgbColor(v, m, x);
+     }
+   };
+ 
+   palette.register(palette.Scheme.withColorFunction(
+     'rainbow', 'qualitative', palette.hsvColor, false, true));
+ 
+   return palette;
+ })();
+ 
+ 
+ /** @typedef {function(number): string} */
+ palette.ColorFunction;
+ 
+ /** @typedef {!Array<string>} */
+ palette.Palette;
+ 
+ /** @typedef {!Object<number, palette.Palette>|!Array<palette.Palette>} */
+ palette.PalettesList;
+ 
+ /**
+  * @typedef {
+  *   function(number, ...?): Array<string>|
+  *   {
+  *     scheme_name: string,
+  *     groups: !Array<string>,
+  *     max: number,
+  *     cbf_max: number,
+  *     addPalette: function(!Array<string>, boolean=),
+  *     addPalettes: function(palette.PalettesList, number=, number=),
+  *     shrinkByTakingHead: function(boolean, number=),
+  *     setColorFunction: function(palette.ColorFunction, boolean=, boolean=),
+  *     color: function(number, ...?): ?string}}
+  */
+ palette.SchemeType;
+ 
+ 
+ /* mpn65 palette start here. ************************************************/
+ 
+ /* The ‘mpn65’ palette is designed for systems which show many graphs which
+    don’t have custom colour palettes chosen by humans or if number of necessary
+    colours isn’t know a priori. */
+ 
+ (function() {
+   var scheme = palette.Scheme.fromPalettes('mpn65', 'qualitative', [[
+     'ff0029', '377eb8', '66a61e', '984ea3', '00d2d5', 'ff7f00', 'af8d00',
+     '7f80cd', 'b3e900', 'c42e60', 'a65628', 'f781bf', '8dd3c7', 'bebada',
+     'fb8072', '80b1d3', 'fdb462', 'fccde5', 'bc80bd', 'ffed6f', 'c4eaff',
+     'cf8c00', '1b9e77', 'd95f02', 'e7298a', 'e6ab02', 'a6761d', '0097ff',
+     '00d067', '000000', '252525', '525252', '737373', '969696', 'bdbdbd',
+     'f43600', '4ba93b', '5779bb', '927acc', '97ee3f', 'bf3947', '9f5b00',
+     'f48758', '8caed6', 'f2b94f', 'eff26e', 'e43872', 'd9b100', '9d7a00',
+     '698cff', 'd9d9d9', '00d27e', 'd06800', '009f82', 'c49200', 'cbe8ff',
+     'fecddf', 'c27eb6', '8cd2ce', 'c4b8d9', 'f883b0', 'a49100', 'f48800',
+     '27d0df', 'a04a9b'
+   ]]);
+   scheme.shrinkByTakingHead(true);
+   palette.register(scheme);
+ })();
+ 
+ /* Paul Tol's schemes start here. *******************************************/
+ /* See http://www.sron.nl/~pault/ */
+ 
+ (function() {
+   var rgb = palette.rgbColor;
+ 
+   /**
+    * Calculates value of a polynomial at given point.
+    * For example, poly(x, 1, 2, 3) calculates value of “1 + 2*x + 3*X²”.
+    * @param {number} x Value to calculate polynomial for.
+    * @param {...number} varargs Coefficients of the polynomial specified in
+    *     the order of rising powers of x including constant as the first
+    *     variable argument.
+    */
+   var poly = function(x, varargs) {
+     var i = arguments.length - 1, n = arguments[i];
+     while (i > 1) {
+       n = n * x + arguments[--i];
+     }
+     return n;
+   };
+ 
+   /**
+    * Calculate approximate value of error function with maximum error of 0.0005.
+    * See <https://en.wikipedia.org/wiki/Error_function>.
+    * @param {number} x Argument of the error function.
+    * @return {number} Value of error function for x.
+    */
+   var erf = function(x) {
+     // https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions
+     // This produces a maximum error of 0.0005 which is more then we need.  In
+     // the worst case, that error is multiplied by four and then divided by two
+     // before being multiplied by 255, so in the end, the error is multiplied by
+     // 510 which produces 0.255 which is less than a single colour step.
+     var y = poly(Math.abs(x), 1, 0.278393, 0.230389, 0.000972, 0.078108);
+     y *= y; // y^2
+     y *= y; // y^4
+     y = 1 - 1 / y;
+     return x < 0 ? -y : y;
+   };
+ 
+   palette.register(palette.Scheme.fromPalettes('tol', 'qualitative', [
+     ['4477aa'],
+     ['4477aa', 'cc6677'],
+     ['4477aa', 'ddcc77', 'cc6677'],
+     ['4477aa', '117733', 'ddcc77', 'cc6677'],
+     ['332288', '88ccee', '117733', 'ddcc77', 'cc6677'],
+     ['332288', '88ccee', '117733', 'ddcc77', 'cc6677', 'aa4499'],
+     ['332288', '88ccee', '44aa99', '117733', 'ddcc77', 'cc6677', 'aa4499'],
+     ['332288', '88ccee', '44aa99', '117733', '999933', 'ddcc77', 'cc6677',
+      'aa4499'],
+     ['332288', '88ccee', '44aa99', '117733', '999933', 'ddcc77', 'cc6677',
+      '882255', 'aa4499'],
+     ['332288', '88ccee', '44aa99', '117733', '999933', 'ddcc77', '661100',
+      'cc6677', '882255', 'aa4499'],
+     ['332288', '6699cc', '88ccee', '44aa99', '117733', '999933', 'ddcc77',
+      '661100', 'cc6677', '882255', 'aa4499'],
+     ['332288', '6699cc', '88ccee', '44aa99', '117733', '999933', 'ddcc77',
+      '661100', 'cc6677', 'aa4466', '882255', 'aa4499']
+   ], 12, 12));
+ 
+   /**
+    * Calculates a colour along Paul Tol's sequential colours axis.
+    * See <http://www.sron.nl/~pault/colourschemes.pdf> figure 7 and equation 1.
+    * @param {number} x Position of the colour on the axis in the [0, 1] range.
+    * @return {string} An RRGGBB representation of the colour.
+    */
+   palette.tolSequentialColor = function(x) {
+     return rgb(1 - 0.392 * (1 + erf((x - 0.869) / 0.255)),
+                1.021 - 0.456 * (1 + erf((x - 0.527) / 0.376)),
+                1 - 0.493 * (1 + erf((x - 0.272) / 0.309)));
+   };
+ 
+   palette.register(palette.Scheme.withColorFunction(
+     'tol-sq', 'sequential', palette.tolSequentialColor, true));
+ 
+   /**
+    * Calculates a colour along Paul Tol's diverging colours axis.
+    * See <http://www.sron.nl/~pault/colourschemes.pdf> figure 8 and equation 2.
+    * @param {number} x Position of the colour on the axis in the [0, 1] range.
+    * @return {string} An RRGGBB representation of the colour.
+    */
+   palette.tolDivergingColor = function(x) {
+     var g = poly(x, 0.572, 1.524, -1.811) / poly(x, 1, -0.291, 0.1574);
+     return rgb(poly(x, 0.235, -2.13, 26.92, -65.5, 63.5, -22.36),
+                g * g,
+                1 / poly(x, 1.579, -4.03, 12.92, -31.4, 48.6, -23.36));
+   };
+ 
+   palette.register(palette.Scheme.withColorFunction(
+     'tol-dv', 'diverging', palette.tolDivergingColor, true));
+ 
+   /**
+    * Calculates a colour along Paul Tol's rainbow colours axis.
+    * See <http://www.sron.nl/~pault/colourschemes.pdf> figure 13 and equation 3.
+    * @param {number} x Position of the colour on the axis in the [0, 1] range.
+    * @return {string} An RRGGBB representation of the colour.
+    */
+   palette.tolRainbowColor = function(x) {
+     return rgb(poly(x, 0.472, -0.567, 4.05) / poly(x, 1, 8.72, -19.17, 14.1),
+                poly(x, 0.108932, -1.22635, 27.284, -98.577, 163.3, -131.395,
+                     40.634),
+                1 / poly(x, 1.97, 3.54, -68.5, 243, -297, 125));
+   };
+ 
+   palette.register(palette.Scheme.withColorFunction(
+     'tol-rainbow', 'qualitative', palette.tolRainbowColor, true));
+ })();
+ 
+ 
+ /* Solarized colour schemes start here. *************************************/
+ /* See http://ethanschoonover.com/solarized */
+ 
+ (function() {
+   /*
+    * Those are not really designed to be used in graphs, but we're keeping
+    * them here in case someone cares.
+    */
+   palette.register(palette.Scheme.fromPalettes('sol-base', 'sequential', [
+     ['002b36', '073642', '586e75', '657b83', '839496', '93a1a1', 'eee8d5',
+      'fdf6e3']
+   ], 1, 8));
+   palette.register(palette.Scheme.fromPalettes('sol-accent', 'qualitative', [
+     ['b58900', 'cb4b16', 'dc322f', 'd33682', '6c71c4', '268bd2', '2aa198',
+      '859900']
+   ]));
+ })();
+ 
+ 
+ /* ColorBrewer colour schemes start here. ***********************************/
+ /* See http://colorbrewer2.org/ */
+ 
+ (function() {
+   var schemes = {
+     YlGn: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['f7fcb9', 'addd8e', '31a354'],
+       4: ['ffffcc', 'c2e699', '78c679', '238443'],
+       5: ['ffffcc', 'c2e699', '78c679', '31a354', '006837'],
+       6: ['ffffcc', 'd9f0a3', 'addd8e', '78c679', '31a354', '006837'],
+       7: ['ffffcc', 'd9f0a3', 'addd8e', '78c679', '41ab5d', '238443',
+           '005a32'],
+       8: ['ffffe5', 'f7fcb9', 'd9f0a3', 'addd8e', '78c679', '41ab5d',
+           '238443', '005a32'],
+       9: ['ffffe5', 'f7fcb9', 'd9f0a3', 'addd8e', '78c679', '41ab5d',
+           '238443', '006837', '004529']
+     },
+     YlGnBu: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['edf8b1', '7fcdbb', '2c7fb8'],
+       4: ['ffffcc', 'a1dab4', '41b6c4', '225ea8'],
+       5: ['ffffcc', 'a1dab4', '41b6c4', '2c7fb8', '253494'],
+       6: ['ffffcc', 'c7e9b4', '7fcdbb', '41b6c4', '2c7fb8', '253494'],
+       7: ['ffffcc', 'c7e9b4', '7fcdbb', '41b6c4', '1d91c0', '225ea8',
+           '0c2c84'],
+       8: ['ffffd9', 'edf8b1', 'c7e9b4', '7fcdbb', '41b6c4', '1d91c0',
+           '225ea8', '0c2c84'],
+       9: ['ffffd9', 'edf8b1', 'c7e9b4', '7fcdbb', '41b6c4', '1d91c0',
+           '225ea8', '253494', '081d58']
+     },
+     GnBu: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['e0f3db', 'a8ddb5', '43a2ca'],
+       4: ['f0f9e8', 'bae4bc', '7bccc4', '2b8cbe'],
+       5: ['f0f9e8', 'bae4bc', '7bccc4', '43a2ca', '0868ac'],
+       6: ['f0f9e8', 'ccebc5', 'a8ddb5', '7bccc4', '43a2ca', '0868ac'],
+       7: ['f0f9e8', 'ccebc5', 'a8ddb5', '7bccc4', '4eb3d3', '2b8cbe',
+           '08589e'],
+       8: ['f7fcf0', 'e0f3db', 'ccebc5', 'a8ddb5', '7bccc4', '4eb3d3',
+           '2b8cbe', '08589e'],
+       9: ['f7fcf0', 'e0f3db', 'ccebc5', 'a8ddb5', '7bccc4', '4eb3d3',
+           '2b8cbe', '0868ac', '084081']
+     },
+     BuGn: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['e5f5f9', '99d8c9', '2ca25f'],
+       4: ['edf8fb', 'b2e2e2', '66c2a4', '238b45'],
+       5: ['edf8fb', 'b2e2e2', '66c2a4', '2ca25f', '006d2c'],
+       6: ['edf8fb', 'ccece6', '99d8c9', '66c2a4', '2ca25f', '006d2c'],
+       7: ['edf8fb', 'ccece6', '99d8c9', '66c2a4', '41ae76', '238b45',
+           '005824'],
+       8: ['f7fcfd', 'e5f5f9', 'ccece6', '99d8c9', '66c2a4', '41ae76',
+           '238b45', '005824'],
+       9: ['f7fcfd', 'e5f5f9', 'ccece6', '99d8c9', '66c2a4', '41ae76',
+           '238b45', '006d2c', '00441b']
+     },
+     PuBuGn: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['ece2f0', 'a6bddb', '1c9099'],
+       4: ['f6eff7', 'bdc9e1', '67a9cf', '02818a'],
+       5: ['f6eff7', 'bdc9e1', '67a9cf', '1c9099', '016c59'],
+       6: ['f6eff7', 'd0d1e6', 'a6bddb', '67a9cf', '1c9099', '016c59'],
+       7: ['f6eff7', 'd0d1e6', 'a6bddb', '67a9cf', '3690c0', '02818a',
+           '016450'],
+       8: ['fff7fb', 'ece2f0', 'd0d1e6', 'a6bddb', '67a9cf', '3690c0',
+           '02818a', '016450'],
+       9: ['fff7fb', 'ece2f0', 'd0d1e6', 'a6bddb', '67a9cf', '3690c0',
+           '02818a', '016c59', '014636']
+     },
+     PuBu: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['ece7f2', 'a6bddb', '2b8cbe'],
+       4: ['f1eef6', 'bdc9e1', '74a9cf', '0570b0'],
+       5: ['f1eef6', 'bdc9e1', '74a9cf', '2b8cbe', '045a8d'],
+       6: ['f1eef6', 'd0d1e6', 'a6bddb', '74a9cf', '2b8cbe', '045a8d'],
+       7: ['f1eef6', 'd0d1e6', 'a6bddb', '74a9cf', '3690c0', '0570b0',
+           '034e7b'],
+       8: ['fff7fb', 'ece7f2', 'd0d1e6', 'a6bddb', '74a9cf', '3690c0',
+           '0570b0', '034e7b'],
+       9: ['fff7fb', 'ece7f2', 'd0d1e6', 'a6bddb', '74a9cf', '3690c0',
+           '0570b0', '045a8d', '023858']
+     },
+     BuPu: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['e0ecf4', '9ebcda', '8856a7'],
+       4: ['edf8fb', 'b3cde3', '8c96c6', '88419d'],
+       5: ['edf8fb', 'b3cde3', '8c96c6', '8856a7', '810f7c'],
+       6: ['edf8fb', 'bfd3e6', '9ebcda', '8c96c6', '8856a7', '810f7c'],
+       7: ['edf8fb', 'bfd3e6', '9ebcda', '8c96c6', '8c6bb1', '88419d',
+           '6e016b'],
+       8: ['f7fcfd', 'e0ecf4', 'bfd3e6', '9ebcda', '8c96c6', '8c6bb1',
+           '88419d', '6e016b'],
+       9: ['f7fcfd', 'e0ecf4', 'bfd3e6', '9ebcda', '8c96c6', '8c6bb1',
+           '88419d', '810f7c', '4d004b']
+     },
+     RdPu: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['fde0dd', 'fa9fb5', 'c51b8a'],
+       4: ['feebe2', 'fbb4b9', 'f768a1', 'ae017e'],
+       5: ['feebe2', 'fbb4b9', 'f768a1', 'c51b8a', '7a0177'],
+       6: ['feebe2', 'fcc5c0', 'fa9fb5', 'f768a1', 'c51b8a', '7a0177'],
+       7: ['feebe2', 'fcc5c0', 'fa9fb5', 'f768a1', 'dd3497', 'ae017e',
+           '7a0177'],
+       8: ['fff7f3', 'fde0dd', 'fcc5c0', 'fa9fb5', 'f768a1', 'dd3497',
+           'ae017e', '7a0177'],
+       9: ['fff7f3', 'fde0dd', 'fcc5c0', 'fa9fb5', 'f768a1', 'dd3497',
+           'ae017e', '7a0177', '49006a']
+     },
+     PuRd: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['e7e1ef', 'c994c7', 'dd1c77'],
+       4: ['f1eef6', 'd7b5d8', 'df65b0', 'ce1256'],
+       5: ['f1eef6', 'd7b5d8', 'df65b0', 'dd1c77', '980043'],
+       6: ['f1eef6', 'd4b9da', 'c994c7', 'df65b0', 'dd1c77', '980043'],
+       7: ['f1eef6', 'd4b9da', 'c994c7', 'df65b0', 'e7298a', 'ce1256',
+           '91003f'],
+       8: ['f7f4f9', 'e7e1ef', 'd4b9da', 'c994c7', 'df65b0', 'e7298a',
+           'ce1256', '91003f'],
+       9: ['f7f4f9', 'e7e1ef', 'd4b9da', 'c994c7', 'df65b0', 'e7298a',
+           'ce1256', '980043', '67001f']
+     },
+     OrRd: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['fee8c8', 'fdbb84', 'e34a33'],
+       4: ['fef0d9', 'fdcc8a', 'fc8d59', 'd7301f'],
+       5: ['fef0d9', 'fdcc8a', 'fc8d59', 'e34a33', 'b30000'],
+       6: ['fef0d9', 'fdd49e', 'fdbb84', 'fc8d59', 'e34a33', 'b30000'],
+       7: ['fef0d9', 'fdd49e', 'fdbb84', 'fc8d59', 'ef6548', 'd7301f',
+           '990000'],
+       8: ['fff7ec', 'fee8c8', 'fdd49e', 'fdbb84', 'fc8d59', 'ef6548',
+           'd7301f', '990000'],
+       9: ['fff7ec', 'fee8c8', 'fdd49e', 'fdbb84', 'fc8d59', 'ef6548',
+           'd7301f', 'b30000', '7f0000']
+     },
+     YlOrRd: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['ffeda0', 'feb24c', 'f03b20'],
+       4: ['ffffb2', 'fecc5c', 'fd8d3c', 'e31a1c'],
+       5: ['ffffb2', 'fecc5c', 'fd8d3c', 'f03b20', 'bd0026'],
+       6: ['ffffb2', 'fed976', 'feb24c', 'fd8d3c', 'f03b20', 'bd0026'],
+       7: ['ffffb2', 'fed976', 'feb24c', 'fd8d3c', 'fc4e2a', 'e31a1c',
+           'b10026'],
+       8: ['ffffcc', 'ffeda0', 'fed976', 'feb24c', 'fd8d3c', 'fc4e2a',
+           'e31a1c', 'b10026'],
+       9: ['ffffcc', 'ffeda0', 'fed976', 'feb24c', 'fd8d3c', 'fc4e2a',
+           'e31a1c', 'bd0026', '800026']
+     },
+     YlOrBr: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['fff7bc', 'fec44f', 'd95f0e'],
+       4: ['ffffd4', 'fed98e', 'fe9929', 'cc4c02'],
+       5: ['ffffd4', 'fed98e', 'fe9929', 'd95f0e', '993404'],
+       6: ['ffffd4', 'fee391', 'fec44f', 'fe9929', 'd95f0e', '993404'],
+       7: ['ffffd4', 'fee391', 'fec44f', 'fe9929', 'ec7014', 'cc4c02',
+           '8c2d04'],
+       8: ['ffffe5', 'fff7bc', 'fee391', 'fec44f', 'fe9929', 'ec7014',
+           'cc4c02', '8c2d04'],
+       9: ['ffffe5', 'fff7bc', 'fee391', 'fec44f', 'fe9929', 'ec7014',
+           'cc4c02', '993404', '662506']
+     },
+     Purples: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['efedf5', 'bcbddc', '756bb1'],
+       4: ['f2f0f7', 'cbc9e2', '9e9ac8', '6a51a3'],
+       5: ['f2f0f7', 'cbc9e2', '9e9ac8', '756bb1', '54278f'],
+       6: ['f2f0f7', 'dadaeb', 'bcbddc', '9e9ac8', '756bb1', '54278f'],
+       7: ['f2f0f7', 'dadaeb', 'bcbddc', '9e9ac8', '807dba', '6a51a3',
+           '4a1486'],
+       8: ['fcfbfd', 'efedf5', 'dadaeb', 'bcbddc', '9e9ac8', '807dba',
+           '6a51a3', '4a1486'],
+       9: ['fcfbfd', 'efedf5', 'dadaeb', 'bcbddc', '9e9ac8', '807dba',
+           '6a51a3', '54278f', '3f007d']
+     },
+     Blues: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['deebf7', '9ecae1', '3182bd'],
+       4: ['eff3ff', 'bdd7e7', '6baed6', '2171b5'],
+       5: ['eff3ff', 'bdd7e7', '6baed6', '3182bd', '08519c'],
+       6: ['eff3ff', 'c6dbef', '9ecae1', '6baed6', '3182bd', '08519c'],
+       7: ['eff3ff', 'c6dbef', '9ecae1', '6baed6', '4292c6', '2171b5',
+           '084594'],
+       8: ['f7fbff', 'deebf7', 'c6dbef', '9ecae1', '6baed6', '4292c6',
+           '2171b5', '084594'],
+       9: ['f7fbff', 'deebf7', 'c6dbef', '9ecae1', '6baed6', '4292c6',
+           '2171b5', '08519c', '08306b']
+     },
+     Greens: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['e5f5e0', 'a1d99b', '31a354'],
+       4: ['edf8e9', 'bae4b3', '74c476', '238b45'],
+       5: ['edf8e9', 'bae4b3', '74c476', '31a354', '006d2c'],
+       6: ['edf8e9', 'c7e9c0', 'a1d99b', '74c476', '31a354', '006d2c'],
+       7: ['edf8e9', 'c7e9c0', 'a1d99b', '74c476', '41ab5d', '238b45',
+           '005a32'],
+       8: ['f7fcf5', 'e5f5e0', 'c7e9c0', 'a1d99b', '74c476', '41ab5d',
+           '238b45', '005a32'],
+       9: ['f7fcf5', 'e5f5e0', 'c7e9c0', 'a1d99b', '74c476', '41ab5d',
+           '238b45', '006d2c', '00441b']
+     },
+     Oranges: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['fee6ce', 'fdae6b', 'e6550d'],
+       4: ['feedde', 'fdbe85', 'fd8d3c', 'd94701'],
+       5: ['feedde', 'fdbe85', 'fd8d3c', 'e6550d', 'a63603'],
+       6: ['feedde', 'fdd0a2', 'fdae6b', 'fd8d3c', 'e6550d', 'a63603'],
+       7: ['feedde', 'fdd0a2', 'fdae6b', 'fd8d3c', 'f16913', 'd94801',
+           '8c2d04'],
+       8: ['fff5eb', 'fee6ce', 'fdd0a2', 'fdae6b', 'fd8d3c', 'f16913',
+           'd94801', '8c2d04'],
+       9: ['fff5eb', 'fee6ce', 'fdd0a2', 'fdae6b', 'fd8d3c', 'f16913',
+           'd94801', 'a63603', '7f2704']
+     },
+     Reds: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['fee0d2', 'fc9272', 'de2d26'],
+       4: ['fee5d9', 'fcae91', 'fb6a4a', 'cb181d'],
+       5: ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15'],
+       6: ['fee5d9', 'fcbba1', 'fc9272', 'fb6a4a', 'de2d26', 'a50f15'],
+       7: ['fee5d9', 'fcbba1', 'fc9272', 'fb6a4a', 'ef3b2c', 'cb181d',
+           '99000d'],
+       8: ['fff5f0', 'fee0d2', 'fcbba1', 'fc9272', 'fb6a4a', 'ef3b2c',
+           'cb181d', '99000d'],
+       9: ['fff5f0', 'fee0d2', 'fcbba1', 'fc9272', 'fb6a4a', 'ef3b2c',
+           'cb181d', 'a50f15', '67000d']
+     },
+     Greys: {
+       type: 'sequential',
+       cbf: 42,
+       3: ['f0f0f0', 'bdbdbd', '636363'],
+       4: ['f7f7f7', 'cccccc', '969696', '525252'],
+       5: ['f7f7f7', 'cccccc', '969696', '636363', '252525'],
+       6: ['f7f7f7', 'd9d9d9', 'bdbdbd', '969696', '636363', '252525'],
+       7: ['f7f7f7', 'd9d9d9', 'bdbdbd', '969696', '737373', '525252',
+           '252525'],
+       8: ['ffffff', 'f0f0f0', 'd9d9d9', 'bdbdbd', '969696', '737373',
+           '525252', '252525'],
+       9: ['ffffff', 'f0f0f0', 'd9d9d9', 'bdbdbd', '969696', '737373',
+           '525252', '252525', '000000']
+     },
+     PuOr: {
+       type: 'diverging',
+       cbf: 42,
+       3: ['f1a340', 'f7f7f7', '998ec3'],
+       4: ['e66101', 'fdb863', 'b2abd2', '5e3c99'],
+       5: ['e66101', 'fdb863', 'f7f7f7', 'b2abd2', '5e3c99'],
+       6: ['b35806', 'f1a340', 'fee0b6', 'd8daeb', '998ec3', '542788'],
+       7: ['b35806', 'f1a340', 'fee0b6', 'f7f7f7', 'd8daeb', '998ec3',
+           '542788'],
+       8: ['b35806', 'e08214', 'fdb863', 'fee0b6', 'd8daeb', 'b2abd2',
+           '8073ac', '542788'],
+       9: ['b35806', 'e08214', 'fdb863', 'fee0b6', 'f7f7f7', 'd8daeb',
+           'b2abd2', '8073ac', '542788'],
+       10: ['7f3b08', 'b35806', 'e08214', 'fdb863', 'fee0b6', 'd8daeb',
+            'b2abd2', '8073ac', '542788', '2d004b'],
+       11: ['7f3b08', 'b35806', 'e08214', 'fdb863', 'fee0b6', 'f7f7f7',
+            'd8daeb', 'b2abd2', '8073ac', '542788', '2d004b']
+     },
+     BrBG: {
+       type: 'diverging',
+       cbf: 42,
+       3: ['d8b365', 'f5f5f5', '5ab4ac'],
+       4: ['a6611a', 'dfc27d', '80cdc1', '018571'],
+       5: ['a6611a', 'dfc27d', 'f5f5f5', '80cdc1', '018571'],
+       6: ['8c510a', 'd8b365', 'f6e8c3', 'c7eae5', '5ab4ac', '01665e'],
+       7: ['8c510a', 'd8b365', 'f6e8c3', 'f5f5f5', 'c7eae5', '5ab4ac',
+           '01665e'],
+       8: ['8c510a', 'bf812d', 'dfc27d', 'f6e8c3', 'c7eae5', '80cdc1',
+           '35978f', '01665e'],
+       9: ['8c510a', 'bf812d', 'dfc27d', 'f6e8c3', 'f5f5f5', 'c7eae5',
+           '80cdc1', '35978f', '01665e'],
+       10: ['543005', '8c510a', 'bf812d', 'dfc27d', 'f6e8c3', 'c7eae5',
+            '80cdc1', '35978f', '01665e', '003c30'],
+       11: ['543005', '8c510a', 'bf812d', 'dfc27d', 'f6e8c3', 'f5f5f5',
+            'c7eae5', '80cdc1', '35978f', '01665e', '003c30']
+     },
+     PRGn: {
+       type: 'diverging',
+       cbf: 42,
+       3: ['af8dc3', 'f7f7f7', '7fbf7b'],
+       4: ['7b3294', 'c2a5cf', 'a6dba0', '008837'],
+       5: ['7b3294', 'c2a5cf', 'f7f7f7', 'a6dba0', '008837'],
+       6: ['762a83', 'af8dc3', 'e7d4e8', 'd9f0d3', '7fbf7b', '1b7837'],
+       7: ['762a83', 'af8dc3', 'e7d4e8', 'f7f7f7', 'd9f0d3', '7fbf7b',
+           '1b7837'],
+       8: ['762a83', '9970ab', 'c2a5cf', 'e7d4e8', 'd9f0d3', 'a6dba0',
+           '5aae61', '1b7837'],
+       9: ['762a83', '9970ab', 'c2a5cf', 'e7d4e8', 'f7f7f7', 'd9f0d3',
+           'a6dba0', '5aae61', '1b7837'],
+       10: ['40004b', '762a83', '9970ab', 'c2a5cf', 'e7d4e8', 'd9f0d3',
+            'a6dba0', '5aae61', '1b7837', '00441b'],
+       11: ['40004b', '762a83', '9970ab', 'c2a5cf', 'e7d4e8', 'f7f7f7',
+            'd9f0d3', 'a6dba0', '5aae61', '1b7837', '00441b']
+     },
+     PiYG: {
+       type: 'diverging',
+       cbf: 42,
+       3: ['e9a3c9', 'f7f7f7', 'a1d76a'],
+       4: ['d01c8b', 'f1b6da', 'b8e186', '4dac26'],
+       5: ['d01c8b', 'f1b6da', 'f7f7f7', 'b8e186', '4dac26'],
+       6: ['c51b7d', 'e9a3c9', 'fde0ef', 'e6f5d0', 'a1d76a', '4d9221'],
+       7: ['c51b7d', 'e9a3c9', 'fde0ef', 'f7f7f7', 'e6f5d0', 'a1d76a',
+           '4d9221'],
+       8: ['c51b7d', 'de77ae', 'f1b6da', 'fde0ef', 'e6f5d0', 'b8e186',
+           '7fbc41', '4d9221'],
+       9: ['c51b7d', 'de77ae', 'f1b6da', 'fde0ef', 'f7f7f7', 'e6f5d0',
+           'b8e186', '7fbc41', '4d9221'],
+       10: ['8e0152', 'c51b7d', 'de77ae', 'f1b6da', 'fde0ef', 'e6f5d0',
+            'b8e186', '7fbc41', '4d9221', '276419'],
+       11: ['8e0152', 'c51b7d', 'de77ae', 'f1b6da', 'fde0ef', 'f7f7f7',
+            'e6f5d0', 'b8e186', '7fbc41', '4d9221', '276419']
+     },
+     RdBu: {
+       type: 'diverging',
+       cbf: 42,
+       3: ['ef8a62', 'f7f7f7', '67a9cf'],
+       4: ['ca0020', 'f4a582', '92c5de', '0571b0'],
+       5: ['ca0020', 'f4a582', 'f7f7f7', '92c5de', '0571b0'],
+       6: ['b2182b', 'ef8a62', 'fddbc7', 'd1e5f0', '67a9cf', '2166ac'],
+       7: ['b2182b', 'ef8a62', 'fddbc7', 'f7f7f7', 'd1e5f0', '67a9cf',
+           '2166ac'],
+       8: ['b2182b', 'd6604d', 'f4a582', 'fddbc7', 'd1e5f0', '92c5de',
+           '4393c3', '2166ac'],
+       9: ['b2182b', 'd6604d', 'f4a582', 'fddbc7', 'f7f7f7', 'd1e5f0',
+           '92c5de', '4393c3', '2166ac'],
+       10: ['67001f', 'b2182b', 'd6604d', 'f4a582', 'fddbc7', 'd1e5f0',
+            '92c5de', '4393c3', '2166ac', '053061'],
+       11: ['67001f', 'b2182b', 'd6604d', 'f4a582', 'fddbc7', 'f7f7f7',
+            'd1e5f0', '92c5de', '4393c3', '2166ac', '053061']
+     },
+     RdGy: {
+       type: 'diverging',
+       cbf: 42,
+       3: ['ef8a62', 'ffffff', '999999'],
+       4: ['ca0020', 'f4a582', 'bababa', '404040'],
+       5: ['ca0020', 'f4a582', 'ffffff', 'bababa', '404040'],
+       6: ['b2182b', 'ef8a62', 'fddbc7', 'e0e0e0', '999999', '4d4d4d'],
+       7: ['b2182b', 'ef8a62', 'fddbc7', 'ffffff', 'e0e0e0', '999999',
+           '4d4d4d'],
+       8: ['b2182b', 'd6604d', 'f4a582', 'fddbc7', 'e0e0e0', 'bababa',
+           '878787', '4d4d4d'],
+       9: ['b2182b', 'd6604d', 'f4a582', 'fddbc7', 'ffffff', 'e0e0e0',
+           'bababa', '878787', '4d4d4d'],
+       10: ['67001f', 'b2182b', 'd6604d', 'f4a582', 'fddbc7', 'e0e0e0',
+            'bababa', '878787', '4d4d4d', '1a1a1a'],
+       11: ['67001f', 'b2182b', 'd6604d', 'f4a582', 'fddbc7', 'ffffff',
+            'e0e0e0', 'bababa', '878787', '4d4d4d', '1a1a1a']
+     },
+     RdYlBu: {
+       type: 'diverging',
+       cbf: 42,
+       3: ['fc8d59', 'ffffbf', '91bfdb'],
+       4: ['d7191c', 'fdae61', 'abd9e9', '2c7bb6'],
+       5: ['d7191c', 'fdae61', 'ffffbf', 'abd9e9', '2c7bb6'],
+       6: ['d73027', 'fc8d59', 'fee090', 'e0f3f8', '91bfdb', '4575b4'],
+       7: ['d73027', 'fc8d59', 'fee090', 'ffffbf', 'e0f3f8', '91bfdb',
+           '4575b4'],
+       8: ['d73027', 'f46d43', 'fdae61', 'fee090', 'e0f3f8', 'abd9e9',
+           '74add1', '4575b4'],
+       9: ['d73027', 'f46d43', 'fdae61', 'fee090', 'ffffbf', 'e0f3f8',
+           'abd9e9', '74add1', '4575b4'],
+       10: ['a50026', 'd73027', 'f46d43', 'fdae61', 'fee090', 'e0f3f8',
+            'abd9e9', '74add1', '4575b4', '313695'],
+       11: ['a50026', 'd73027', 'f46d43', 'fdae61', 'fee090', 'ffffbf',
+            'e0f3f8', 'abd9e9', '74add1', '4575b4', '313695']
+     },
+     Spectral: {
+       type: 'diverging',
+       cbf: 0,
+       3: ['fc8d59', 'ffffbf', '99d594'],
+       4: ['d7191c', 'fdae61', 'abdda4', '2b83ba'],
+       5: ['d7191c', 'fdae61', 'ffffbf', 'abdda4', '2b83ba'],
+       6: ['d53e4f', 'fc8d59', 'fee08b', 'e6f598', '99d594', '3288bd'],
+       7: ['d53e4f', 'fc8d59', 'fee08b', 'ffffbf', 'e6f598', '99d594',
+           '3288bd'],
+       8: ['d53e4f', 'f46d43', 'fdae61', 'fee08b', 'e6f598', 'abdda4',
+           '66c2a5', '3288bd'],
+       9: ['d53e4f', 'f46d43', 'fdae61', 'fee08b', 'ffffbf', 'e6f598',
+           'abdda4', '66c2a5', '3288bd'],
+       10: ['9e0142', 'd53e4f', 'f46d43', 'fdae61', 'fee08b', 'e6f598',
+            'abdda4', '66c2a5', '3288bd', '5e4fa2'],
+       11: ['9e0142', 'd53e4f', 'f46d43', 'fdae61', 'fee08b', 'ffffbf',
+            'e6f598', 'abdda4', '66c2a5', '3288bd', '5e4fa2']
+     },
+     RdYlGn: {
+       type: 'diverging',
+       cbf: 0,
+       3: ['fc8d59', 'ffffbf', '91cf60'],
+       4: ['d7191c', 'fdae61', 'a6d96a', '1a9641'],
+       5: ['d7191c', 'fdae61', 'ffffbf', 'a6d96a', '1a9641'],
+       6: ['d73027', 'fc8d59', 'fee08b', 'd9ef8b', '91cf60', '1a9850'],
+       7: ['d73027', 'fc8d59', 'fee08b', 'ffffbf', 'd9ef8b', '91cf60',
+           '1a9850'],
+       8: ['d73027', 'f46d43', 'fdae61', 'fee08b', 'd9ef8b', 'a6d96a',
+           '66bd63', '1a9850'],
+       9: ['d73027', 'f46d43', 'fdae61', 'fee08b', 'ffffbf', 'd9ef8b',
+           'a6d96a', '66bd63', '1a9850'],
+       10: ['a50026', 'd73027', 'f46d43', 'fdae61', 'fee08b', 'd9ef8b',
+            'a6d96a', '66bd63', '1a9850', '006837'],
+       11: ['a50026', 'd73027', 'f46d43', 'fdae61', 'fee08b', 'ffffbf',
+            'd9ef8b', 'a6d96a', '66bd63', '1a9850', '006837']
+     },
+     Accent: {
+       type: 'qualitative',
+       cbf: 0,
+       3: ['7fc97f', 'beaed4', 'fdc086'],
+       4: ['7fc97f', 'beaed4', 'fdc086', 'ffff99'],
+       5: ['7fc97f', 'beaed4', 'fdc086', 'ffff99', '386cb0'],
+       6: ['7fc97f', 'beaed4', 'fdc086', 'ffff99', '386cb0', 'f0027f'],
+       7: ['7fc97f', 'beaed4', 'fdc086', 'ffff99', '386cb0', 'f0027f',
+           'bf5b17'],
+       8: ['7fc97f', 'beaed4', 'fdc086', 'ffff99', '386cb0', 'f0027f',
+           'bf5b17', '666666']
+     },
+     Dark2: {
+       type: 'qualitative',
+       cbf: 3,
+       3: ['1b9e77', 'd95f02', '7570b3'],
+       4: ['1b9e77', 'd95f02', '7570b3', 'e7298a'],
+       5: ['1b9e77', 'd95f02', '7570b3', 'e7298a', '66a61e'],
+       6: ['1b9e77', 'd95f02', '7570b3', 'e7298a', '66a61e', 'e6ab02'],
+       7: ['1b9e77', 'd95f02', '7570b3', 'e7298a', '66a61e', 'e6ab02',
+           'a6761d'],
+       8: ['1b9e77', 'd95f02', '7570b3', 'e7298a', '66a61e', 'e6ab02',
+           'a6761d', '666666']
+     },
+     Paired: {
+       type: 'qualitative',
+       cbf: 4,
+       3: ['a6cee3', '1f78b4', 'b2df8a'],
+       4: ['a6cee3', '1f78b4', 'b2df8a', '33a02c'],
+       5: ['a6cee3', '1f78b4', 'b2df8a', '33a02c', 'fb9a99'],
+       6: ['a6cee3', '1f78b4', 'b2df8a', '33a02c', 'fb9a99', 'e31a1c'],
+       7: ['a6cee3', '1f78b4', 'b2df8a', '33a02c', 'fb9a99', 'e31a1c',
+           'fdbf6f'],
+       8: ['a6cee3', '1f78b4', 'b2df8a', '33a02c', 'fb9a99', 'e31a1c',
+           'fdbf6f', 'ff7f00'],
+       9: ['a6cee3', '1f78b4', 'b2df8a', '33a02c', 'fb9a99', 'e31a1c',
+           'fdbf6f', 'ff7f00', 'cab2d6'],
+       10: ['a6cee3', '1f78b4', 'b2df8a', '33a02c', 'fb9a99', 'e31a1c',
+            'fdbf6f', 'ff7f00', 'cab2d6', '6a3d9a'],
+       11: ['a6cee3', '1f78b4', 'b2df8a', '33a02c', 'fb9a99', 'e31a1c',
+            'fdbf6f', 'ff7f00', 'cab2d6', '6a3d9a', 'ffff99'],
+       12: ['a6cee3', '1f78b4', 'b2df8a', '33a02c', 'fb9a99', 'e31a1c',
+            'fdbf6f', 'ff7f00', 'cab2d6', '6a3d9a', 'ffff99', 'b15928']
+     },
+     Pastel1: {
+       type: 'qualitative',
+       cbf: 0,
+       3: ['fbb4ae', 'b3cde3', 'ccebc5'],
+       4: ['fbb4ae', 'b3cde3', 'ccebc5', 'decbe4'],
+       5: ['fbb4ae', 'b3cde3', 'ccebc5', 'decbe4', 'fed9a6'],
+       6: ['fbb4ae', 'b3cde3', 'ccebc5', 'decbe4', 'fed9a6', 'ffffcc'],
+       7: ['fbb4ae', 'b3cde3', 'ccebc5', 'decbe4', 'fed9a6', 'ffffcc',
+           'e5d8bd'],
+       8: ['fbb4ae', 'b3cde3', 'ccebc5', 'decbe4', 'fed9a6', 'ffffcc',
+           'e5d8bd', 'fddaec'],
+       9: ['fbb4ae', 'b3cde3', 'ccebc5', 'decbe4', 'fed9a6', 'ffffcc',
+           'e5d8bd', 'fddaec', 'f2f2f2']
+     },
+     Pastel2: {
+       type: 'qualitative',
+       cbf: 0,
+       3: ['b3e2cd', 'fdcdac', 'cbd5e8'],
+       4: ['b3e2cd', 'fdcdac', 'cbd5e8', 'f4cae4'],
+       5: ['b3e2cd', 'fdcdac', 'cbd5e8', 'f4cae4', 'e6f5c9'],
+       6: ['b3e2cd', 'fdcdac', 'cbd5e8', 'f4cae4', 'e6f5c9', 'fff2ae'],
+       7: ['b3e2cd', 'fdcdac', 'cbd5e8', 'f4cae4', 'e6f5c9', 'fff2ae',
+           'f1e2cc'],
+       8: ['b3e2cd', 'fdcdac', 'cbd5e8', 'f4cae4', 'e6f5c9', 'fff2ae',
+           'f1e2cc', 'cccccc']
+     },
+     Set1: {
+       type: 'qualitative',
+       cbf: 0,
+       3: ['e41a1c', '377eb8', '4daf4a'],
+       4: ['e41a1c', '377eb8', '4daf4a', '984ea3'],
+       5: ['e41a1c', '377eb8', '4daf4a', '984ea3', 'ff7f00'],
+       6: ['e41a1c', '377eb8', '4daf4a', '984ea3', 'ff7f00', 'ffff33'],
+       7: ['e41a1c', '377eb8', '4daf4a', '984ea3', 'ff7f00', 'ffff33',
+           'a65628'],
+       8: ['e41a1c', '377eb8', '4daf4a', '984ea3', 'ff7f00', 'ffff33',
+           'a65628', 'f781bf'],
+       9: ['e41a1c', '377eb8', '4daf4a', '984ea3', 'ff7f00', 'ffff33',
+           'a65628', 'f781bf', '999999']
+     },
+     Set2: {
+       type: 'qualitative',
+       cbf: 3,
+       3: ['66c2a5', 'fc8d62', '8da0cb'],
+       4: ['66c2a5', 'fc8d62', '8da0cb', 'e78ac3'],
+       5: ['66c2a5', 'fc8d62', '8da0cb', 'e78ac3', 'a6d854'],
+       6: ['66c2a5', 'fc8d62', '8da0cb', 'e78ac3', 'a6d854', 'ffd92f'],
+       7: ['66c2a5', 'fc8d62', '8da0cb', 'e78ac3', 'a6d854', 'ffd92f',
+           'e5c494'],
+       8: ['66c2a5', 'fc8d62', '8da0cb', 'e78ac3', 'a6d854', 'ffd92f',
+           'e5c494', 'b3b3b3']
+     },
+     Set3: {
+       type: 'qualitative',
+       cbf: 0,
+       3: ['8dd3c7', 'ffffb3', 'bebada'],
+       4: ['8dd3c7', 'ffffb3', 'bebada', 'fb8072'],
+       5: ['8dd3c7', 'ffffb3', 'bebada', 'fb8072', '80b1d3'],
+       6: ['8dd3c7', 'ffffb3', 'bebada', 'fb8072', '80b1d3', 'fdb462'],
+       7: ['8dd3c7', 'ffffb3', 'bebada', 'fb8072', '80b1d3', 'fdb462',
+           'b3de69'],
+       8: ['8dd3c7', 'ffffb3', 'bebada', 'fb8072', '80b1d3', 'fdb462',
+           'b3de69', 'fccde5'],
+       9: ['8dd3c7', 'ffffb3', 'bebada', 'fb8072', '80b1d3', 'fdb462',
+           'b3de69', 'fccde5', 'd9d9d9'],
+       10: ['8dd3c7', 'ffffb3', 'bebada', 'fb8072', '80b1d3', 'fdb462',
+            'b3de69', 'fccde5', 'd9d9d9', 'bc80bd'],
+       11: ['8dd3c7', 'ffffb3', 'bebada', 'fb8072', '80b1d3', 'fdb462',
+            'b3de69', 'fccde5', 'd9d9d9', 'bc80bd', 'ccebc5'],
+       12: ['8dd3c7', 'ffffb3', 'bebada', 'fb8072', '80b1d3', 'fdb462',
+            'b3de69', 'fccde5', 'd9d9d9', 'bc80bd', 'ccebc5', 'ffed6f']
+     },
+     Custom1: {
+       type: 'qualitative',
+       cbf: 0,
+       1: ['3aa5ff'],
+       2: ['42d4f4', 'f032e6'],
+       3: ['f96a00', 'ffa866', 'ffd4b3'],
+       5: ['ffcd22', '911db4', '373737','ff0058','469990'],
+       6: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4'],
+       7: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4', '42d4f4'],
+       8: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4', '42d4f4',
+           '469990'],
+       9: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4', '42d4f4',
+           '469990','e6bdff'],
+       10: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4', '42d4f4',
+            '469990','e6bdff','9a6324'],
+       11: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4', '42d4f4',
+            '469990','e6bdff','9a6324','fffac8'],
+       12: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4', '42d4f4',
+            '469990','e6bdff','9a6324','fffac8','800000'],
+       18: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4', '42d4f4',
+            '469990','e6bdff','9a6324','fffac8','800000','aaffc3','808001',
+            'bfef45','000075','fabebe','a9a9a9'],
+       20: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4', '42d4f4',
+            '469990','e6bdff','9a6324','fffac8','800000','aaffc3','808001',
+            'bfef45','000075','fabebe','a9a9a9','000000','f032e6','ffd7b1'],
+       50: ['e6194b','3cb44b','ffcd22','4364d8','f58230','911db4', '42d4f4',
+            '469990','e6bdff','9a6324','fffac8','800000','aaffc3','808001',
+            'bfef45','000075','fabebe','a9a9a9','000000','f032e6','ffd7b1'],
+     },
+     BasePalette: {
+       type: 'qualitative',
+       cbf: 0,
+       1: ['024BA3'],
+       2: ['024BA3', 'E24577'],
+       3: ['024BA3', 'E24577', 'F58834'],
+       5: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC'],
+       6: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4'],
+       7: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4', '00D88B'],
+       8: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4', '00D88B', '8AE770'],
+       9: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4', '00D88B', '8AE770', 'B93F94'],
+       10: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4', '00D88B', '8AE770', 'B93F94', 'E24577'],
+       11: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4', '00D88B', '8AE770', 'B93F94', 'E24577', 'F56155'],
+       12: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4', '00D88B', '8AE770', 'B93F94', 'E24577', 'F56155', 'F58834'],
+       18: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4', '00D88B', '8AE770', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834'],
+       20: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4', '00D88B', '8AE770', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4'],
+       50: ['024BA3', '0068BE', '0082CB', '019AC9', '02B1BC', '00C6A4', '00D88B', '8AE770', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4'],
+     },
+     BasePalette2: {
+       type: 'qualitative',
+       cbf: 0,
+       1: ['F3457E'],
+       2: ['024BA3', '7B47A4'],
+       3: ['024BA3', '7B47A4', 'B93F94'],
+       5: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155'],
+       6: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834'],
+       7: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3'],
+       8: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4'],
+       9: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94'],
+       10: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577'],
+       11: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155'],
+       12: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834'],
+       18: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834'],
+       20: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4'],
+       50: ['024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4', 'B93F94', 'E24577', 'F56155', 'F58834', '024BA3', '7B47A4'],
+     },
+   };
+ 
+   for (var name in schemes) {
+     var scheme = schemes[name];
+     scheme = palette.Scheme.fromPalettes(
+       'cb-' + name, [scheme.type, 'cb-' + scheme.type], scheme, 12, scheme.cbf);
+     palette.register(scheme);
+   }
+ })();
+ 
+ if(typeof module === "object" && module.exports) {
+   module.exports = palette
+ }
+ 
\ No newline at end of file
diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx
index 73a78d54a0ccdf8a82bd8872a66dae4dac236e30..eafe618723ba6bf1aa631679ade9742b9c93b59b 100644
--- a/src/components/common/Header.tsx
+++ b/src/components/common/Header.tsx
@@ -142,6 +142,14 @@ class Header extends Component<LoginProps, LoginState> {
                       }`}>ALL APPLICATIONS</Link>
                   </li>
                 )}
+                 {Helper.getUserRole() === APP.ROLE.REGULATOR && (
+                  <li className="mr-5">
+                    <Link to={"/analytics"} className={`${this.props.history.location.pathname.match("/analytics")
+                      ? "active"
+                      : ""
+                      }`}>DASHBOARD</Link>
+                  </li>
+                )}
               </ul>
               }
               {
diff --git a/src/constants/ApiConstants.ts b/src/constants/ApiConstants.ts
index 0dfc07744aaeca45db4d66558cca97fefd2dbb91..80e50ca6883a1d5b51a3fa66206d8a4566ee043b 100644
--- a/src/constants/ApiConstants.ts
+++ b/src/constants/ApiConstants.ts
@@ -33,4 +33,9 @@ export const APIS = {
     GET_USER_BY_ID: "user/getUserById",
     GET_ALL_USERS: "user/v1/getAllUser",
   },
+  DASHBOARD: {
+    GET_DASHBOARD_CONFIG: "dashboard/getDashboardConfig/SMF/home",
+    GET_DASHBOARD_PROFILE: "dashboard/getDashboardsForProfile/SMF",
+    GET_CHART_DATA: "dashboard/getChartV2/SMF",
+  },
 };
diff --git a/src/helpers/exportChart.js b/src/helpers/exportChart.js
new file mode 100644
index 0000000000000000000000000000000000000000..b6f9c21dbd31af39e77cb2ad71e4a6ed2b17a452
--- /dev/null
+++ b/src/helpers/exportChart.js
@@ -0,0 +1,103 @@
+import NFormatterFun from "../components/charts/NFormatterFun";
+const ExportChart = {
+  _charts: {},
+
+  setAttribute(key, value) {
+    this._charts[key] = value;
+  },
+
+  getRows(chartCode) {
+    var rows = [];
+    var chartData = this._charts[chartCode][0].plots;
+    var tempVal;
+    chartData.forEach((d1, i) => {
+      if (i === 0) {
+        if (d1.parentLabel !== null && d1.parentLabel !== "") {
+          rows.push([d1.label, d1.valueLabel, d1.parentLabel]);
+        } else {
+          rows.push([d1.label, d1.valueLabel]);
+        }
+      }
+      tempVal = NFormatterFun(d1.value, d1.symbol, "Unit");
+      tempVal =
+        typeof tempVal == "string"
+          ? parseFloat(tempVal.replace(/,/g, ""))
+          : tempVal;
+      if (d1.parentName !== null && d1.parentName !== "") {
+        rows.push([d1.name, tempVal, d1.parentName]);
+      } else {
+        rows.push([d1.name, tempVal]);
+      }
+    });
+
+    return rows;
+  },
+
+  tableToCsv(filename) {
+    var tableParentId = "#" + filename.replace(/\s/g, "");
+    var csv = [];
+    var rows = document.querySelectorAll(tableParentId + " table tr");
+    if (rows.length === 0 && rows !== undefined) {
+      rows = document.querySelectorAll("#modalView table tr");
+    }
+    for (var i = 0; i < rows.length; i++) {
+      var row = [],
+        cols = rows[i].querySelectorAll("td, th");
+
+      for (var j = 0; j < cols.length; j++)
+        row.push(cols[j].innerText.replace(/,/g, ""));
+
+      csv.push(row.join(","));
+    }
+
+    // Download CSV file
+    this.downloadCSV(csv.join("\n"), filename);
+  },
+
+  toCsv(filename, chartCode) {
+    var rows = this.getRows(chartCode);
+    var processRow = function (row) {
+      var finalVal = "";
+      for (var j = 0; j < row.length; j++) {
+        var innerValue = row[j] === null ? "" : row[j].toString();
+        if (row[j] instanceof Date) {
+          innerValue = row[j].toLocaleString();
+        }
+        var result = innerValue.replace(/"/g, '""');
+        if (result.search(/("|,|\n)/g) >= 0) result = '"' + result + '"';
+        if (j > 0) finalVal += ",";
+        finalVal += result;
+      }
+      return finalVal + "\n";
+    };
+
+    var csvFile = "";
+    for (var i = 0; i < rows.length; i++) {
+      csvFile += processRow(rows[i]);
+    }
+    this.downloadCSV(csvFile, filename);
+  },
+
+  downloadCSV(csvFile, filename) {
+    var blob = new Blob([csvFile], { type: "text/csv;charset=utf-8;" });
+    if (navigator.msSaveBlob) {
+      // IE 10+
+      navigator.msSaveBlob(blob, filename);
+    } else {
+      var link = document.createElement("a");
+      if (link.download !== undefined) {
+        // feature detection
+        // Browsers that support HTML5 download attribute
+        var url = URL.createObjectURL(blob);
+        link.setAttribute("href", url);
+        link.setAttribute("download", filename + ".csv");
+        link.style.visibility = "hidden";
+        document.body.appendChild(link);
+        link.click();
+        document.body.removeChild(link);
+      }
+    }
+  },
+};
+
+export default ExportChart;
diff --git a/src/index.tsx b/src/index.tsx
index bdacd3935c16656dcde08f021127974067fdc332..3b91690a14ec1f22f440c1fd7b64490c4ec2c8f4 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,4 +1,5 @@
 import 'bootstrap/dist/css/bootstrap.css';
+import 'bootstrap/dist/js/bootstrap.js';
 import React from 'react';
 import ReactDOM from 'react-dom';
 import './index.css';
diff --git a/src/layouts/Dashboard/DashboardLayout.tsx b/src/layouts/Dashboard/DashboardLayout.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..cbefac85a582acd5b947a0413a2eaaf42947630d
--- /dev/null
+++ b/src/layouts/Dashboard/DashboardLayout.tsx
@@ -0,0 +1,56 @@
+/*eslint-disable no-empty-pattern*/
+// @ts-nocheck
+import _ from "lodash";
+import PageLayout from "./PageLayout";
+import { useHistory } from "react-router-dom";
+import WidgetNavBar from "../../components/charts/WidgetNavBar";
+
+/**
+ * DashboardLayout component renders
+ * the visualisations based on the configurations
+ * for regulator
+ */
+
+interface DashboardLayoutProps {
+  dashboardConfig: any;
+}
+
+export const DashboardLayout = ({ dashboardConfig }: DashboardLayoutProps) => {
+  let history = useHistory();
+
+  const renderCharts = () => {
+    let dashboardConfigData: any = dashboardConfig;
+
+    let tabsInitData = _.chain(dashboardConfigData)
+      .first()
+      .get("visualizations")
+      .groupBy("name")
+      .value();
+
+    return (
+      <div>
+        {_.map(tabsInitData, (k, v) => {
+          return (
+            <PageLayout
+              key={v}
+              chartRowData={k}
+              row={k.row}
+              pathName={history.location.pathname}
+            />
+          );
+        })}
+      </div>
+    );
+  };
+
+  return (
+    <div className="">
+      <div className="">
+        <WidgetNavBar history={history}/>
+      </div>
+      <div className="row pt-2">
+        {dashboardConfig.length > 0 && renderCharts()}
+      </div>
+    </div>
+  );
+};
diff --git a/src/layouts/Dashboard/PageLayout.js b/src/layouts/Dashboard/PageLayout.js
new file mode 100644
index 0000000000000000000000000000000000000000..0ece9fd561a9f3b6256882bf3a2491349db7aca1
--- /dev/null
+++ b/src/layouts/Dashboard/PageLayout.js
@@ -0,0 +1,34 @@
+import React, { Component } from "react";
+import GenericCharts from "../../components/charts/GenericCharts";
+
+/**
+ * Page layout to display the charts which are generated dynamically
+ */
+
+class PageLayout extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      data: null,
+    };
+  }
+
+  render() {
+    let { chartRowData, row } = this.props;
+
+    return (
+      <div key={`generic${row}`}>
+        {chartRowData.map((vizData, j) => (
+          <GenericCharts
+            key={j}
+            row={row}
+            chartData={vizData}
+            pathProps={this.props.pathName}
+          />
+        ))}
+      </div>
+    );
+  }
+}
+
+export default PageLayout;
diff --git a/src/layouts/Inspector/FormView.tsx b/src/layouts/Inspector/FormView.tsx
index 38cedb83317132e043e2015fcfc41abd4a393d97..6afd451a602ffff63555806be2bdebd7bde776ff 100644
--- a/src/layouts/Inspector/FormView.tsx
+++ b/src/layouts/Inspector/FormView.tsx
@@ -291,8 +291,10 @@ export const FormView = ({ applicationData, formData }: FormViewProps) => {
             setModalInspectionValue(m.inspectionValue);
             if (status === "correct") {
               m.isCorrect = true;
-              m.comments = m.comments;
-              m.inspectionValue = m.inspectionValue;
+              m.comments = "";
+              m.inspectionValue = "";
+              setModalTextArea("");
+              setModalInspectionValue("");
             } else if (status === "incorrect") {
               m.isCorrect = false;
               m.comments = m.comments;
diff --git a/src/layouts/index.ts b/src/layouts/index.ts
index 113d4eda6eba35037f11172716b5d895fe22d6ea..bf2607aa8173cc3de95b2fb521cb90fe4355d84e 100644
--- a/src/layouts/index.ts
+++ b/src/layouts/index.ts
@@ -6,3 +6,4 @@ export { ReviewApplicationLayout } from "./Regulator/ReviewApplicationLayout";
 export { InspectionSummaryLayout } from "./Inspector/InspectionSummaryLayout";
 export { InspectionCompleteLayout } from "./Inspector/InspectionCompleteLayout";
 export { ConsentFormView } from "./Inspector/ConsentFormView";
+export { DashboardLayout } from "./Dashboard/DashboardLayout";
diff --git a/src/pages/Dashboard/Landing.tsx b/src/pages/Dashboard/Landing.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..66fb27f591e654a3922020c7a4e1085e2e99e821
--- /dev/null
+++ b/src/pages/Dashboard/Landing.tsx
@@ -0,0 +1,60 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+import { Fragment, useEffect, useState } from "react";
+import { HeadingOne } from "../../components/headings";
+import Header from "../../components/common/Header";
+import { useHistory } from "react-router-dom";
+import { DashboardLayout } from "../../layouts";
+import { ChartService } from "../../services";
+import { APP } from "../../constants";
+import Notify from "../../helpers/notify";
+
+/**
+ * Landing component renders
+ * dashboard layout and its UI components
+ */
+
+interface LandingProps {
+  data?: any;
+}
+
+export const Landing = ({ data }: LandingProps) => {
+  let history = useHistory();
+
+  const [dashboardConfigData, setDashboardConfigData] = useState<any[]>([]);
+  const [trigger, setTrigger] = useState(false);
+  const [toggle, setToggle] = useState(false);
+  const [showFilters, setShowFilters] = useState(false);
+
+  useEffect(() => {
+    getDashboardConfigurations();
+  }, []);
+
+  const getDashboardConfigurations = () => {
+    ChartService.getDashboardConfig().then((response) => {
+      if (response.statusInfo.statusCode === APP.CODE.SUCCESS) {
+        setDashboardConfigData(response.responseData)
+      } else {
+        Notify.error(response.statusInfo.errorMessage);
+      }
+    });
+  };
+
+  return (
+    <Fragment>
+      <Header history={history} />
+      <div className="container-fluid">
+        <div className="container dashboard-inner-container mt-4">
+          {/* Section one */}
+          <section className="pt-3">
+            <HeadingOne heading="Insights so far" />
+          </section>
+
+          {/* Dashboards */}
+          <section className="">
+            <DashboardLayout dashboardConfig={dashboardConfigData}/>
+          </section>
+        </div>
+      </div>
+    </Fragment>
+  );
+};
diff --git a/src/pages/Inspector/InspectorApplications.tsx b/src/pages/Inspector/InspectorApplications.tsx
index 3bc76a0d291628ac290da457f23fd7d3e06c35d4..9445c927f51dd9a866343058dd1a1996dfe741de 100644
--- a/src/pages/Inspector/InspectorApplications.tsx
+++ b/src/pages/Inspector/InspectorApplications.tsx
@@ -151,6 +151,7 @@ export const InspectorApplications = ({ data }: InspectorApplicationsProps) => {
                   userDetails && userDetails.id
                 )
               ) {
+                // consol
                 i.inspection.assignedTo.map((m: any, n: number) => {
                   if (m.id === userDetails.id) {
                     // if (m.status === LANG.FORM_STATUS.INSPECTION_COMPLETED) {
diff --git a/src/pages/index.ts b/src/pages/index.ts
index 038393ffa67aa325558c449fbe42b8850af26258..fd7753a899f221f49ac3c275d7faccd2df9b86ce 100644
--- a/src/pages/index.ts
+++ b/src/pages/index.ts
@@ -6,3 +6,4 @@ export { ReviewApplication } from "./Regulator/ReviewApplication";
 export { InspectionSummary } from "./Inspector/InspectionSummary";
 export { InspectionComplete } from "./Inspector/InspectionComplete";
 export { ViewConsentApplications } from "./Inspector/ViewConsentApplication";
+export { Landing } from "./Dashboard/Landing";
diff --git a/src/services/chart.service.js b/src/services/chart.service.js
new file mode 100644
index 0000000000000000000000000000000000000000..7200b96b33a657534abab7db7657cbc739d7b8f8
--- /dev/null
+++ b/src/services/chart.service.js
@@ -0,0 +1,75 @@
+import { APIS, APP, LANG } from "../constants";
+import { authHeader } from "../helpers/authHeader";
+import Notify from "./../helpers/notify";
+import { UserService } from "./user.service";
+
+/**
+ * Chart service
+ * Provides API functions, returns
+ * data required for the charts
+ */
+
+export const ChartService = {
+  getDashboardConfig,
+  getDashboardProfile,
+  getChartData,
+};
+
+async function getDashboardConfig() {
+  const requestOptions = {
+    method: APP.REQUEST.GET,
+    headers: authHeader(),
+  };
+  return await fetch(
+    APIS.BASE_URL + APIS.DASHBOARD.GET_DASHBOARD_CONFIG,
+    requestOptions
+  ).then(handleResponse);
+}
+
+async function getDashboardProfile() {
+  const requestOptions = {
+    method: APP.REQUEST.GET,
+    headers: authHeader(),
+  };
+  return await fetch(
+    APIS.BASE_URL + APIS.DASHBOARD.GET_DASHBOARD_PROFILE,
+    requestOptions
+  ).then(handleResponse);
+}
+
+async function getChartData(payload) {
+  const requestOptions = {
+    method: APP.REQUEST.POST,
+    body: JSON.stringify(payload),
+    headers: authHeader(),
+  };
+  return await fetch(
+    APIS.BASE_URL + APIS.DASHBOARD.GET_CHART_DATA,
+    requestOptions
+  ).then(handleResponse);
+}
+
+function handleResponse(response) {
+  return response.text().then((text) => {
+    const data = text && JSON.parse(text);
+    if (!response.ok) {
+      const error =
+        LANG.APIERROR ||
+        (data && data.statusInfo && data.statusInfo.errorMessage) ||
+        response.statusText;
+      return Promise.reject(new Error(error));
+    }
+    if (data && data.statusInfo && data.statusInfo.statusCode) {
+      if (data.statusInfo.statusCode === 306) {
+        const error =
+          (data && data.statusInfo && data.statusInfo.errorMessage) ||
+          response.statusText;
+        UserService.logout();
+        Notify.error(error.message);
+        window.location.reload();
+        return Promise.reject(new Error(error));
+      }
+    }
+    return data;
+  });
+}
diff --git a/src/services/index.ts b/src/services/index.ts
index c9237033708069aa301f56d9c545488a1182ec2b..53c49458eed0f020f8790ed0225bfa1e22d078f4 100644
--- a/src/services/index.ts
+++ b/src/services/index.ts
@@ -1,3 +1,4 @@
 export { ReviewService } from "./review.service";
 export { FormService } from "./form.service";
 export { UserService } from "./user.service";
+export { ChartService } from "./chart.service";
diff --git a/src/styles/chart.css b/src/styles/chart.css
new file mode 100644
index 0000000000000000000000000000000000000000..269f0066cab901b66ed19406db039084a9454ffc
--- /dev/null
+++ b/src/styles/chart.css
@@ -0,0 +1,57 @@
+@import url("./colors.css");
+@import url("../assets/fonts/fonts.css");
+
+.chart_title_one {
+  color: var(--black-87);
+  font-family: "Montserrat-SemiBold";
+  font-size: 1rem;
+  letter-spacing: 0.12px;
+  line-height: 1.5;
+}
+
+.chart_card_one {
+  background-color: var(--white-100);
+  border: 1px solid var(--black-08);
+  border-radius: 4px;
+  padding: 1.75rem;
+}
+
+.widget_card_one {
+  background-color: var(--white-100);
+  border-radius: 4px;
+  border: 1px solid var(--black-08);
+  min-height: 5.563rem;
+}
+
+.widget_card_one label {
+  color: var(--black-87);
+  font-family: "Lato-Regular";
+  font-size: 0.875rem;
+  letter-spacing: 0.25px;
+  line-height: 1.5;
+}
+
+.widget_card_one h2 {
+  color: var(--black-87);
+  font-family: "Montserrat-SemiBold";
+  font-size: 1.25rem;
+  letter-spacing: 0.12px;
+  line-height: 1.4;
+}
+
+.custom_cursor {
+  cursor: pointer;
+}
+
+.dropdown_text {
+  font-family: "Lato-Regular";
+  font-size: 0.875rem;
+}
+
+.chart_card_description_one {
+  color: var(--black-60);
+  font-family:"Lato-Regular";
+  font-size: 0.875rem;
+  letter-spacing: 0.25;
+  line-height: 1.429;
+}
diff --git a/yarn.lock b/yarn.lock
index 12a63aa67e1d6a7eb61d1fd968db17787c76c378..f97eb311c7636315f113951dd6e21cc536029b72 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1315,6 +1315,11 @@
     schema-utils "^3.0.0"
     source-map "^0.7.3"
 
+"@popperjs/core@^2.11.4":
+  version "2.11.4"
+  resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.4.tgz#d8c7b8db9226d2d7664553a0741ad7d0397ee503"
+  integrity sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg==
+
 "@rollup/plugin-babel@^5.2.0":
   version "5.3.0"
   resolved "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz"
@@ -1720,6 +1725,11 @@
   resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
   integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
 
+"@types/lodash@^4.14.118":
+  version "4.14.180"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670"
+  integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g==
+
 "@types/mime@^1":
   version "1.3.2"
   resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz"
@@ -2782,6 +2792,16 @@ char-regex@^2.0.0:
   resolved "https://registry.npmjs.org/char-regex/-/char-regex-2.0.0.tgz"
   integrity sha512-oGu2QekBMXgyQNWPDRQ001bjvDnZe4/zBTz37TMbiKz1NbNiyiH5hRkobe7npRN6GfbGbxMYFck/vQ1r9c1VMA==
 
+chart.js@^3.4.0:
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.7.1.tgz#0516f690c6a8680c6c707e31a4c1807a6f400ada"
+  integrity sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==
+
+chartjs-plugin-datalabels@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.0.0.tgz#caacefb26803d968785071eab012dde8746c5939"
+  integrity sha512-WBsWihphzM0Y8fmQVm89+iy99mmgejmj5/jcsYqwxSioLRL/zqJ4Scv/eXq5ZqvG3TpojlGzZLeaOaSvDm7fwA==
+
 check-types@^11.1.1:
   version "11.1.2"
   resolved "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz"
@@ -3499,6 +3519,11 @@ dom-serializer@^1.0.1:
     domhandler "^4.2.0"
     entities "^2.0.0"
 
+dom-to-image@^2.6.0:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/dom-to-image/-/dom-to-image-2.6.0.tgz#8a503608088c87b1c22f9034ae032e1898955867"
+  integrity sha1-ilA2CAiMh7HCL5A0rgMuGJiVWGc=
+
 domelementtype@1:
   version "1.3.1"
   resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz"
@@ -3992,6 +4017,11 @@ execa@^5.0.0:
     signal-exit "^3.0.3"
     strip-final-newline "^2.0.0"
 
+exenv@^1.2.0:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
+  integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=
+
 exit@^0.1.2:
   version "0.1.2"
   resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz"
@@ -4105,6 +4135,11 @@ file-loader@^6.2.0:
     loader-utils "^2.0.0"
     schema-utils "^3.0.0"
 
+file-saver@^2.0.5:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
+  integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
+
 filelist@^1.0.1:
   version "1.0.2"
   resolved "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz"
@@ -5694,12 +5729,12 @@ lodash.uniq@^4.5.0:
   resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz"
   integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
 
-lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
+lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
   version "4.17.21"
   resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
   integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
 
-loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
   version "1.4.0"
   resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
   integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -6987,6 +7022,11 @@ react-app-polyfill@^3.0.0:
     regenerator-runtime "^0.13.9"
     whatwg-fetch "^3.6.2"
 
+react-chartjs-2@^3.0.3:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-3.3.0.tgz#3f62681645acccc1ab27a9186c70f79d6d417f73"
+  integrity sha512-4Mt0SR2aiUbWi/4762odRBYSnbNKSs4HWc0o3IW43py5bMfmfpeZU95w6mbvtuLZH/M3GsPJMU8DvDc+5U9blQ==
+
 react-confirm-alert@^2.7.0:
   version "2.7.0"
   resolved "https://registry.yarnpkg.com/react-confirm-alert/-/react-confirm-alert-2.7.0.tgz#7cdbf2e052e03554ac6a7d8956c9c227010c8a53"
@@ -7046,6 +7086,11 @@ react-is@^17.0.1:
   resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
   integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
 
+react-lifecycles-compat@^3.0.0:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
+  integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
+
 react-loadable@^5.5.0:
   version "5.5.0"
   resolved "https://registry.npmjs.org/react-loadable/-/react-loadable-5.5.0.tgz"
@@ -7060,6 +7105,16 @@ react-localization@^1.0.17:
   dependencies:
     localized-strings "^0.2.0"
 
+react-modal@^3.14.4:
+  version "3.14.4"
+  resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.14.4.tgz#2ca7e8e9a180955e5c9508c228b73167c1e6f6a3"
+  integrity sha512-8surmulejafYCH9wfUmFyj4UfbSJwjcgbS9gf3oOItu4Hwd6ivJyVBETI0yHRhpJKCLZMUtnhzk76wXTsNL6Qg==
+  dependencies:
+    exenv "^1.2.0"
+    prop-types "^15.7.2"
+    react-lifecycles-compat "^3.0.0"
+    warning "^4.0.3"
+
 react-refresh@^0.11.0:
   version "0.11.0"
   resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz"
@@ -8412,6 +8467,13 @@ walker@^1.0.7:
   dependencies:
     makeerror "1.0.12"
 
+warning@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
+  integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
+  dependencies:
+    loose-envify "^1.0.0"
+
 watchpack@^2.3.1:
   version "2.3.1"
   resolved "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz"