Repository: eslam-gomaa/kptop (language: python)

Issue:
refactor KPtop docs



Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 24eacff..99e5f1d 100644
--- a/README.md
+++ b/README.md
@@ -57,18 +57,51 @@ pip3 install kptop --upgrade
 ## Environment Variables
 <a id=env></a>
 
+| ENV | Description                                                                          | Default | Required |
+| ----- | -------------------------------------------------------------------------------------- | --------- | ---------- |
+| `KPTOP_CONNECTION_METHOD`    | The way to connect to Prometheus server<br />**options:** ['prometheus_endpoint', 'pod_portForward'] | <br />      | Yes      |
 
-| ENV                              | Description                                                  | Default | Required |
-| -------------------------------- | ------------------------------------------------------------ | ------- | -------- |
-| `KPTOP_PROMETHEUS_SERVER`        | Prometheus server URL                                        |         | Yes      |
-| `KPTOP_BASIC_AUTH_ENABLED`       | Whether basic authentication is needed to connect to Prometheus | False   | No       |
-| `KPTOP_PROMETHEUS_USERNAME`      | Prometheus username                                          |         | No       |
-| `KPTOP_PROMETHEUS_PASSWORD`      | Prometheus password                                          |         | No       |
-| `KPTOP_INSECURE`                 | Verify SSL certificate                                       | False   | No       |
-| `KPTOP_NODE_EXPORTER_NODE_LABEL` | node exporter "node label"                                   | "node"  | NO       |
-| `KPTOP_START_GRAPHS_WITH_ZERO`   | By default graphs begin with '0'  to let the graph take its full hight | True    | NO       |
-| `KPTOP_LOGGING_DIR`              | Choose a different logging directory                         | /tmp/   | NO       |
-| `KPTOP_GRAPH_WIDTH`              | Choose a custom graphs width                                 | 45      | NO       |
+There are 2 options to connect KPtop to Prometheus:
+1. With a Prometheus server endpoint
+    - Suitable if Prometheus is exposed (with an ingress for example)
+2. With 'K8s pod port-forward' (Through K8s API-Server)
+    - Suitable if Prometheus is Not exposed (Only rechable within the K8s cluster)
+
+
+#### `prometheus_endpoint` ENVs
+
+| ENV | Description                                                     | Default | Required |
+| ----- | ----------------------------------------------------------------- | --------- | ---------- |
+| `KPTOP_PROMETHEUS_SERVER`    | Prometheus server URL                                           |         | Yes      |
+| `KPTOP_BASIC_AUTH_ENABLED`    | Whether basic authentication is needed to connect to Prometheus | False   | No       |
+| `KPTOP_PROMETHEUS_USERNAME`    | Prometheus username                                             |         | No       |
+| `KPTOP_PROMETHEUS_PASSWORD`    | Prometheus password                                             |         | No       |
+| `KPTOP_INSECURE`    | Verify SSL certificate                                          | False   | No       |
+
+
+<br>
+
+#### `pod_portForward` ENVs
+
+| ENV | Description                                            | Default | Required |
+| ----- | -------------------------------------------------------- | --------- | ---------- |
+| `KPTOP_PROMETHEUS_POD_NAME`    | Prometheus pod name                                    |         | Yes      |
+| `KPTOP_PROMETHEUS_POD_PORT`    | Prometheus port number                                 | 9090    | No       |
+| `KPTOP_PROMETHEUS_POD_NAMESPACE`    | The name space in which the Prometheus pod is deployed | default | No       |
+| `KUBECONFIG`    | custom K8s kube config file                            | *default path*        | No       |
+
+
+<br>
+
+#### General ENVs
+
+
+| ENV | Description                                                            | Default | Required |
+| ----- | ------------------------------------------------------------------------ | --------- | ---------- |
+| `KPTOP_NODE_EXPORTER_NODE_LABEL`    | node exporter "node label"                                             | "node"  | NO       |
+| `KPTOP_START_GRAPHS_WITH_ZERO`    | By default graphs begin with '0'  to let the graph take its full hight | True    | NO       |
+| `KPTOP_LOGGING_DIR`    | Choose a different logging directory                                   | /tmp/   | NO       |
+| `KPTOP_GRAPH_WIDTH`    | Choose a custom graphs width                                           | 45      | NO       |
 
 
 <br>
@@ -96,18 +129,24 @@ pip3 install kptop --upgrade
 
 ## Usage
 
+
 <br>
 
-Different ways to connect to Prometheus server:
-1. You have direct access to it (Like in dev environments)
-2. Prometheus is exposed publically/over-vpn (mostly with an Ingress)
-3. You can use [kubectl port-forward command](./docs/port-forward.md)
-4. You also can run `kptop` as a Kubernetes pod  (to be built))
+Add the ENVs and you're good to go.
 
+_*Examples*_
 
-<br>
+```bash
+export KPTOP_CONNECTION_METHOD="pod_portForward"
+export KPTOP_PROMETHEUS_POD_NAME="my-prometheus-server-0"
+export KPTOP_PROMETHEUS_POD_PORT="9090"
+export KPTOP_PROMETHEUS_POD_NAMESPACE="monitoring"
+```
+
+> Or
 
 ```bash
+export KPTOP_CONNECTION_METHOD="prometheus_endpoint"
 export KPTOP_PROMETHEUS_SERVER="http://prometheus.home-lab.com"
 ```
 
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000..6f37c11
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,2 @@
+.idea
+_site
\ No newline at end of file
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000..466466b
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,156 @@
+# https://github.com/just-the-docs/just-the-docs/blob/main/_config.yml
+
+# theme: jekyll-theme-cayman
+remote_theme: "just-the-docs/just-the-docs@v0.7.0" # https://github.com/just-the-docs/just-the-docs/releases
+permalink: pretty
+
+exclude:
+  # from https://github.com/jekyll/jekyll/blob/master/lib/site_template/_config.yml:
+  - .sass-cache/
+  - .jekyll-cache/
+  - gemfiles/
+  - Gemfile
+  - Gemfile.lock
+  - node_modules/
+  - vendor/bundle/
+  - vendor/cache/
+  - vendor/gems/
+  - vendor/ruby/
+  # specific to the theme website:
+  - bin/
+  - lib/
+  - "*.gemspec"
+  - "*.gem"
+  - LICENSE.txt
+  - package.json
+  - package-lock.json
+  - Rakefile
+  - README.md
+  - CODE_OF_CONDUCT.md
+  - docker-compose.yml
+  - Dockerfile
+  # theme test code
+  - fixtures/
+
+search_enabled: true
+search:
+  # Split pages into sections that can be searched individually
+  # Supports 1 - 6, default: 2
+  heading_level: 2
+  # Maximum amount of previews per search result
+  # Default: 3
+  previews: 2
+  # Maximum amount of words to display before a matched word in the preview
+  # Default: 5
+  preview_words_before: 3
+  # Maximum amount of words to display after a matched word in the preview
+  # Default: 10
+  preview_words_after: 3
+  # Set the search token separator
+  # Default: /[\s\-/]+/
+  #   ample: enable support for hyphenated search words
+  tokenizer_separator: /[\s/]+/
+  # Display the relative url in search results
+  # Supports true (default) or false
+  rel_url: true
+  # Enable or disable the search button that appears in the bottom right corner of every page
+  # Supports true or false (default)
+  button: false
+
+# For copy button on code
+enable_copy_code_button: true
+
+# By default, consuming the theme as a gem leaves mermaid disabled; it is opt-in
+mermaid:
+  # Version of mermaid library
+  # Pick an available version from https://cdn.jsdelivr.net/npm/mermaid/
+  version: "9.1.3"
+  # Put any additional configuration, such as setting the theme, in _includes/mermaid_config.js
+  # See also docs/ui-components/code
+  # To load mermaid from a local library, also use the `path` key to specify the location of the library; e.g.
+  # for (v10+):
+  # path: "/assets/js/mermaid.esm.min.mjs"
+  # for (<v10):
+  # path: "/assets/js/mermaid.min.js"
+  # Note: copy both `mermaid.esm.min.mjs` (v10+) or `mermaid.min.js` (<v10) and the associated `.map` file from the specified version of `mermaid/dist` to `/assets/js/`.
+
+heading_anchors: true
+
+# Aux links for the upper right navigation
+aux_links:
+  "KPtop Docs on GitHub":
+    - "https://github.com/eslam-gomaa/kptop"
+
+# Makes Aux links open in a new tab. Default is false
+aux_links_new_tab: false
+
+# Sort order for navigation links
+# nav_sort: case_insensitive # default, equivalent to nil
+nav_sort: case_sensitive # Capital letters sorted before lowercase
+
+# External navigation links
+# nav_external_links:
+#   - title: Just the Docs on GitHub
+#     url: https://github.com/just-the-docs/just-the-docs
+
+nav_external_links:
+  - title: KPtop on GitHub
+    url: https://github.com/eslam-gomaa/kptop
+
+# Back to top link
+back_to_top: true
+back_to_top_text: "Back to top"
+
+footer_content: 'Copyright &copy; 2017-2020 Patrick Marsceill. Distributed by an <a href="https://github.com/just-the-docs/just-the-docs/tree/main/LICENSE.txt">MIT license.</a>'
+
+# Footer last edited timestamp
+last_edit_timestamp: true # show or hide edit time - page must have `last_modified_date` defined in the frontmatter
+last_edit_time_format: "%b %e %Y at %I:%M %p" # uses ruby's time format: https://ruby-doc.org/stdlib-2.7.0/libdoc/time/rdoc/Time.html
+
+# Footer "Edit this page on GitHub" link text
+gh_edit_link: true # show or hide edit this page link
+gh_edit_link_text: "Edit this page on GitHub"
+gh_edit_repository: "https://github.com/just-the-docs/just-the-docs" # the github URL for your repo
+gh_edit_branch: "main" # the branch that your docs is served from
+# gh_edit_source: docs # the source that your files originate from
+gh_edit_view_mode: "tree" # "tree" or "edit" if you want the user to jump into the editor immediately
+
+# Color scheme currently only supports "dark", "light"/nil (default), or a custom scheme that you define
+color_scheme: nil
+
+callouts_level: quiet # or loud
+callouts:
+  highlight:
+    color: yellow
+  important:
+    title: Important
+    color: blue
+  new:
+    title: New
+    color: green
+  note:
+    title: Note
+    color: purple
+  warning:
+    title: Warning
+    color: red
+
+plugins:
+  - jekyll-seo-tag
+  - jekyll-github-metadata
+  - jekyll-include-cache
+
+kramdown:
+  syntax_highlighter_opts:
+    block:
+      line_numbers: false
+
+compress_html:
+  clippings: all
+  comments: all
+  endings: all
+  startings: []
+  blanklines: false
+  profile: false
+  # ignore:
+  #   envs: all
diff --git a/docs/_includes/_config.yml b/docs/_includes/_config.yml
new file mode 100644
index 0000000..d1d4b00
--- /dev/null
+++ b/docs/_includes/_config.yml
@@ -0,0 +1,7 @@
+pagination:
+  enabled: true
+  per_page: 9
+  permalink: '/page/:num/'
+  title: ':title - page :num'
+  sort_field: 'date'
+  sort_reverse: true
\ No newline at end of file
diff --git a/docs/_includes/components/aux_nav.html b/docs/_includes/components/aux_nav.html
new file mode 100644
index 0000000..f327da6
--- /dev/null
+++ b/docs/_includes/components/aux_nav.html
@@ -0,0 +1,15 @@
+<nav aria-label="Auxiliary" class="aux-nav">
+  <ul class="aux-nav-list">
+    {% for link in site.aux_links %}
+      <li class="aux-nav-list-item">
+        <a href="{{ link.last }}" class="site-button"
+          {% if site.aux_links_new_tab %}
+          target="_blank" rel="noopener noreferrer"
+          {% endif %}
+        >
+          {{ link.first }}
+        </a>
+      </li>
+    {% endfor %}
+  </ul>
+</nav>
diff --git a/docs/_includes/components/breadcrumbs.html b/docs/_includes/components/breadcrumbs.html
new file mode 100644
index 0000000..82ad6bd
--- /dev/null
+++ b/docs/_includes/components/breadcrumbs.html
@@ -0,0 +1,43 @@
+{%- comment -%}
+  Include as: {%- include components/breadcrumbs.html -%}
+  Depends on: page, site.
+  Results in: HTML for the breadcrumbs component.
+  Overwrites:
+    pages_list, parent_page, grandparent_page.
+{%- endcomment -%}
+
+{%- if page.url != "/" and page.parent -%}
+
+  {%- assign pages_list = site[page.collection]
+      | default: site.html_pages
+      | where_exp: "item", "item.title != nil"
+      | where_exp: "item", "item.has_children != nil" -%}
+
+  {%- if page.grand_parent -%}
+    {%- assign parent_page = pages_list
+        | where: "title", page.parent
+        | where: "parent", page.grand_parent
+        | first -%}
+    {%- assign grandparent_page = pages_list
+        | where: "title", page.grand_parent
+        | first -%}
+  {%- else -%}
+    {%- assign parent_page = pages_list
+        | where: "title", page.parent
+        | where_exp: "item", "item.parent == nil"
+        | first -%}
+  {%- endif -%}
+
+<nav aria-label="Breadcrumb" class="breadcrumb-nav">
+  <ol class="breadcrumb-nav-list">
+  {% if page.parent -%}
+  {%- if page.grand_parent %}
+    <li class="breadcrumb-nav-list-item"><a href="{{ grandparent_page.url | relative_url }}">{{ page.grand_parent }}</a></li>
+  {%- endif %}
+    <li class="breadcrumb-nav-list-item"><a href="{{ parent_page.url | relative_url }}">{{ page.parent }}</a></li>
+  {% endif -%}
+    <li class="breadcrumb-nav-list-item"><span>{{ page.title }}</span></li>
+  </ol>
+</nav>
+
+{%- endif -%}
diff --git a/docs/_includes/components/children_nav.html b/docs/_includes/components/children_nav.html
new file mode 100644
index 0000000..ce2482a
--- /dev/null
+++ b/docs/_includes/components/children_nav.html
@@ -0,0 +1,33 @@
+{%- comment -%}
+  Include as: {%- include components/children_nav.html -%}
+  Depends on: page, site.
+  Results in: HTML for the children-navigation component.
+  Includes:
+    sorted_pages.html
+    toc_heading_custom.html
+  Overwrites:
+    child_pages.
+{%- endcomment -%}
+
+{%- if page.has_children == true and page.has_toc != false -%}
+  {%- assign child_pages = site[page.collection]
+        | default: site.html_pages
+        | where: "parent", page.title
+        | where: "grand_parent", page.parent -%}
+
+  {%- include sorted_pages.html pages = child_pages -%}
+
+  {%- if page.child_nav_order == 'desc' or page.child_nav_order == 'reversed' -%}
+    {%- assign sorted_pages = sorted_pages | reverse -%}
+  {%- endif -%}
+{%- endif -%}
+
+<hr>
+{% include toc_heading_custom.html %}
+<ul>
+{% for child in sorted_pages %}
+  <li>
+    <a href="{{ child.url | relative_url }}">{{ child.title }}</a>{% if child.summary %} - {{ child.summary }}{% endif %}
+  </li>
+{% endfor %}
+</ul>
diff --git a/docs/_includes/components/footer.html b/docs/_includes/components/footer.html
new file mode 100644
index 0000000..01b2c23
--- /dev/null
+++ b/docs/_includes/components/footer.html
@@ -0,0 +1,34 @@
+{% capture footer_custom %}
+  {%- include footer_custom.html -%}
+{% endcapture %}
+{% if footer_custom != "" or site.last_edit_timestamp or site.gh_edit_link %}
+  <hr>
+  <footer>
+    {% if site.back_to_top %}
+      <p><a href="#top" id="back-to-top">{{ site.back_to_top_text }}</a></p>
+    {% endif %}
+
+    {{ footer_custom }}
+
+    {% if site.last_edit_timestamp or site.gh_edit_link %}
+      <div class="d-flex mt-2">
+        {% if site.last_edit_timestamp and site.last_edit_time_format and page.last_modified_date %}
+          <p class="text-small text-grey-dk-000 mb-0 mr-2">
+            Page last modified: <span class="d-inline-block">{{ page.last_modified_date | date: site.last_edit_time_format }}</span>.
+          </p>
+        {% endif %}
+        {% if
+          site.gh_edit_link and
+          site.gh_edit_link_text and
+          site.gh_edit_repository and
+          site.gh_edit_branch and
+          site.gh_edit_view_mode
+        %}
+          <p class="text-small text-grey-dk-000 mb-0">
+            <a href="{{ site.gh_edit_repository }}/{{ site.gh_edit_view_mode }}/{{ site.gh_edit_branch }}{% if site.gh_edit_source %}/{{ site.gh_edit_source }}{% endif %}{% if page.collection and site.collections_dir %}/{{ site.collections_dir }}{% endif %}/{{ page.path }}" id="edit-this-page">{{ site.gh_edit_link_text }}</a>
+          </p>
+        {% endif %}
+      </div>
+    {% endif %}
+  </footer>
+{% endif %}
diff --git a/docs/_includes/components/header.html b/docs/_includes/components/header.html
new file mode 100644
index 0000000..f9c3386
--- /dev/null
+++ b/docs/_includes/components/header.html
@@ -0,0 +1,11 @@
+<div id="main-header" class="main-header">
+  {% if site.search_enabled != false %}
+    {% include components/search_header.html %}
+  {% else %}
+    <div></div>
+  {% endif %}
+  {% include header_custom.html %}
+  {% if site.aux_links %}
+    {% include components/aux_nav.html %}
+  {% endif %}
+</div>
diff --git a/docs/_includes/components/mermaid.html b/docs/_includes/components/mermaid.html
new file mode 100644
index 0000000..a99a563
--- /dev/null
+++ b/docs/_includes/components/mermaid.html
@@ -0,0 +1,45 @@
+{% comment %}
+The complexity of this file comes from a breaking change in Mermaid v10; mermaid.init has been deprecated (and supposedly, didn't work earlier?).
+
+So, we check whether the user's Mermaid version is >= 10; if not, we fall back to the previous init syntax.
+
+If a user is using a custom mermaid file and doesn't specify a version, we default to the < v10 behaviour. Users who use version v10 or above should specify this in the version key.
+{% endcomment %}
+
+{% if site.mermaid.version %}
+  {% assign mermaid_major_version = site.mermaid.version | split: "." | first | plus: 0 %}
+{% else %}
+  {% assign mermaid_major_version = 9 %}
+{% endif %}
+
+{% if mermaid_major_version > 9 %}
+
+<script type="module">
+  {% if site.mermaid.path %}
+  import mermaid from '{{ site.mermaid.path | relative_url }}';
+  {% else %}
+  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@{{ site.mermaid.version }}/dist/mermaid.esm.min.mjs';
+  {% endif %}
+
+  var config = {% include mermaid_config.js %};
+  mermaid.initialize(config);
+  mermaid.run({
+    querySelector: '.language-mermaid',
+  });
+</script>
+
+{% else %}
+
+{% if site.mermaid.path %}
+  <script src="{{ site.mermaid.path | relative_url }}"></script>
+{% else %}
+  <script src="https://cdn.jsdelivr.net/npm/mermaid@{{ site.mermaid.version }}/dist/mermaid.min.js"></script>
+{% endif %}
+
+<script>
+  var config = {% include mermaid_config.js %};
+  mermaid.initialize(config);
+  window.mermaid.init(undefined, document.querySelectorAll('.language-mermaid'));
+</script>
+
+{% endif %}
diff --git a/docs/_includes/components/search_footer.html b/docs/_includes/components/search_footer.html
new file mode 100644
index 0000000..d448fdb
--- /dev/null
+++ b/docs/_includes/components/search_footer.html
@@ -0,0 +1,7 @@
+{% if site.search.button %}
+<button id="search-button" class="search-button btn-reset" aria-label="Focus on search">
+  <svg viewBox="0 0 24 24" class="icon" aria-hidden="true"><use xlink:href="#svg-search"></use></svg>
+</button>
+{% endif %}
+
+<div class="search-overlay"></div>
diff --git a/docs/_includes/components/search_header.html b/docs/_includes/components/search_header.html
new file mode 100644
index 0000000..3562124
--- /dev/null
+++ b/docs/_includes/components/search_header.html
@@ -0,0 +1,9 @@
+{% capture search_placeholder %}{% include search_placeholder_custom.html %}{% endcapture %}
+
+<div class="search" role="search">
+  <div class="search-input-wrap">
+    <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="{{ search_placeholder | strip_html | strip }}" aria-label="{{ search_placeholder | strip_html| strip }}" autocomplete="off">
+    <label for="search-input" class="search-label"><svg viewBox="0 0 24 24" class="search-icon"><use xlink:href="#svg-search"></use></svg></label>
+  </div>
+  <div id="search-results" class="search-results"></div>
+</div>
diff --git a/docs/_includes/components/sidebar.html b/docs/_includes/components/sidebar.html
new file mode 100644
index 0000000..7863340
--- /dev/null
+++ b/docs/_includes/components/sidebar.html
@@ -0,0 +1,83 @@
+{%- comment -%}
+  Include as: {%- include components/sidebar.html -%}
+  Depends on: page(?), site.
+  Results in: HTML for the side bar.
+  Includes:
+    title.html, nav.html, nav_footer_custom.html
+  Overwrites: 
+    pages_top_size, collections_size, collection_entry,
+    collection_key, collection_value, collection, nav_footer_custom.
+  Should not be cached, because nav_footer_custom.html might depend on page.
+{%- endcomment -%}
+
+<div class="side-bar">
+  <div class="site-header" role="banner">
+    <a href="{{ '/' | relative_url }}" class="site-title lh-tight">{% include title.html %}</a>
+    <button id="menu-button" class="site-button btn-reset" aria-label="Toggle menu" aria-pressed="false">
+      <svg viewBox="0 0 24 24" class="icon" aria-hidden="true"><use xlink:href="#svg-menu"></use></svg>
+    </button>
+  </div>
+  <nav aria-label="Main" id="site-nav" class="site-nav">
+    {% assign pages_top_size = site.html_pages
+          | where_exp:"item", "item.title != nil"
+          | where_exp:"item", "item.parent == nil"
+          | where_exp:"item", "item.nav_exclude != true"
+          | size %}
+    {% if pages_top_size > 0 %}
+      {% include_cached nav.html pages=site.html_pages %}
+    {% endif %}
+    {%- if site.nav_external_links -%}
+      <ul class="nav-list">
+        {%- for node in site.nav_external_links -%}
+          <li class="nav-list-item external">
+            <a href="{{ node.url | absolute_url }}" class="nav-list-link external">
+              {{ node.title }}
+              {% unless node.hide_icon %}<svg viewBox="0 0 24 24" aria-labelledby="svg-external-link-title"><use xlink:href="#svg-external-link"></use></svg>{% endunless %}
+            </a>
+          </li>
+        {%- endfor -%}
+      </ul>
+    {%- endif -%}
+    {% if site.just_the_docs.collections %}
+      {% assign collections_size = site.just_the_docs.collections | size %}
+      {% for collection_entry in site.just_the_docs.collections %}
+        {% assign collection_key = collection_entry[0] %}
+        {% assign collection_value = collection_entry[1] %}
+        {% assign collection = site[collection_key] %}
+        {% if collection_value.nav_exclude != true %}
+          {% if collections_size > 1 or pages_top_size > 0 %}
+            {% if collection_value.nav_fold == true %}
+              <ul class="nav-list nav-category-list">
+                <li class="nav-list-item{% if page.collection == collection_key %} active{% endif %}">
+                  {%- if collection.size > 0 -%}
+                  <button class="nav-list-expander btn-reset" aria-label="Toggle collection {{ collection_value.name }}" aria-pressed="{% if page.collection == collection_key %}true{% else %}false{% endif %}">
+                    <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg>
+                  </button>
+                  {%- endif -%}
+                  <div class="nav-category">{{ collection_value.name }}</div>
+                  {% include_cached nav.html pages=collection %}
+                </li>
+              </ul>
+            {% else %}
+              <div class="nav-category">{{ collection_value.name }}</div>
+              {% include_cached nav.html pages=collection %}
+            {% endif %}
+          {% else %}
+            {% include_cached nav.html pages=collection %}
+          {% endif %}
+        {% endif %}
+      {% endfor %}
+    {% endif %}
+  </nav>
+
+  {% capture nav_footer_custom %}
+    {%- include nav_footer_custom.html -%}
+  {% endcapture %}
+  {% if nav_footer_custom != "" %}
+    {{ nav_footer_custom }}
+  {% else %}
+    <footer class="site-footer">
+      This site uses <a href="https://github.com/just-the-docs/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll.
+    </footer>
+  {% endif %}
+</div>
diff --git a/docs/_includes/css/activation.scss.liquid b/docs/_includes/css/activation.scss.liquid
new file mode 100644
index 0000000..055a763
--- /dev/null
+++ b/docs/_includes/css/activation.scss.liquid
@@ -0,0 +1,172 @@
+{%- comment -%}
+  Include as: {%- include css/activation.scss.liquid -%}
+  Depends on: page, site.
+  Results in: page-dependent SCSS rules for inclusion in a head style element.
+  Includes:
+    sorted_pages.html.
+  Overwrites: 
+    activation_pages, activation_pages_top_size, activation_page, activation_title,
+    activation_first_level, activation_second_level, activation_third_level,
+    activation_first_level_reversed, activation_second_level_reversed,
+    activation_first_level_index, activation_second_level_index, activation_third_level_index.
+  Should not be cached, because it depends on page.
+  (For a site with only top-level pages, the rendering of this file is always empty.
+  This property could be detected, and might halve the build time for such sites.)
+{%- endcomment -%}
+
+{%- unless page.title == nil or page.nav_exclude == true -%}
+
+{%- assign activation_pages = site[page.collection]
+      | default: site.html_pages
+      | where_exp: "item", "item.title != nil"
+      | where_exp: "item", "item.nav_exclude != true" -%}
+
+{%- assign activation_first_level_index = nil -%}
+{%- assign activation_second_level_index = nil -%}
+{%- assign activation_third_level_index = nil -%}
+{%- assign activation_first_level_reversed = nil -%}
+{%- assign activation_second_level_reversed = nil -%}
+
+{%- assign activation_title = page.grand_parent | default: page.parent | default: page.title -%}
+{%- assign activation_first_level = activation_pages
+      | where_exp: "item", "item.parent == nil" -%}
+{%- include sorted_pages.html pages = activation_first_level -%}
+{%- for activation_page in sorted_pages -%}
+  {%- if activation_page.title == activation_title -%}
+    {%- assign activation_first_level_index = forloop.index -%}
+    {%- assign activation_first_level_reversed = activation_page.child_nav_order -%}
+    {%- break -%}
+  {%- endif -%}
+{%- endfor -%}
+
+{%- unless activation_first_level_index == nil -%}
+
+{%- if page.grand_parent -%}
+  {%- assign activation_title = page.parent -%}
+  {%- assign activation_second_level = activation_pages
+        | where_exp: "item", "item.grand_parent == nil"
+        | where_exp: "item", "item.parent == page.grand_parent" -%}
+{%- elsif page.parent -%}
+  {%- assign activation_title = page.title -%}
+  {%- assign activation_second_level = activation_pages
+        | where_exp: "item", "item.grand_parent == nil"
+        | where_exp: "item", "item.parent == page.parent" -%}
+{%- endif -%}
+{%- if page.parent -%}
+  {%- include sorted_pages.html pages = activation_second_level -%}
+  {%- for activation_page in sorted_pages -%}
+    {%- if activation_page.title == activation_title -%}
+      {%- assign activation_second_level_index = forloop.index -%}
+      {%- assign activation_second_level_reversed = activation_page.child_nav_order -%}
+      {%- if activation_first_level_reversed -%}
+        {%- assign activation_second_level_index = sorted_pages | size | plus: 1 | minus: activation_second_level_index -%}
+      {%- endif -%}
+      {%- break -%}
+    {%- endif -%}
+  {%- endfor -%}
+{%- endif -%}
+
+{%- if page.grand_parent -%}
+  {%- assign activation_third_level = activation_pages
+        | where_exp: "item", "item.parent == page.parent"
+        | where_exp: "item", "item.grand_parent == page.grand_parent" -%}
+  {%- include sorted_pages.html pages = activation_third_level -%}
+  {%- assign activation_third_level = sorted_pages -%}
+  {%- for activation_page in sorted_pages -%}
+    {%- if activation_page.title == page.title -%}
+      {%- assign activation_third_level_index = forloop.index -%}
+      {%- if activation_second_level_reversed -%}
+        {%- assign activation_third_level_index = sorted_pages | size | plus: 1 | minus: activation_third_level_index -%}
+      {%- endif -%}
+      {%- break -%}
+    {%- endif -%}
+  {%- endfor -%}
+{%- endif -%}
+
+{%- unless activation_second_level_index == nil and activation_third_level_index -%}
+
+{%- if page.collection == nil -%}
+
+  {%- capture activation_collection_prefix -%}
+  .site-nav > .nav-list:nth-child(1):not(.nav-category-list) 
+  {%- endcapture -%}
+
+{%- else -%}
+
+  {%- for activation_collection in site.just_the_docs.collections -%}
+    {%- if activation_collection[0] == page.collection -%}
+      {%- assign activation_collection_index = forloop.index -%}
+      {%- break -%}
+    {%- endif -%}
+  {%- endfor -%}
+  {%- assign activation_index = activation_collection_index -%}
+  {%- assign activation_pages_top_size = site.html_pages
+          | where_exp:"item", "item.title != nil"
+          | where_exp:"item", "item.parent == nil"
+          | where_exp:"item", "item.nav_exclude != true"
+          | size -%}
+  {%- if activation_pages_top_size > 0  -%}
+    {%- assign activation_index = activation_index | plus: 1 -%}
+  {%- endif -%}
+  {%- if site.nav_external_links -%}
+    {%- assign activation_index = activation_index | plus: 1 -%}
+  {%- endif -%}
+  {%- capture activation_collection_prefix -%}
+  .site-nav > .nav-list:nth-of-type({{ activation_index }}){% if site.just_the_docs.collections[page.collection].nav_fold == true %} > .nav-list-item > .nav-list{% endif %}
+  {%- endcapture -%}
+  
+{%- endif -%}
+
+// Styling for the nav-list-link to the current page:
+{{ activation_collection_prefix }} {
+  > .nav-list-item:not(.external):nth-child({{ activation_first_level_index }}){%- if activation_second_level_index %} > .nav-list > .nav-list-item:nth-child({{ activation_second_level_index }}){%- if activation_third_level_index %} > .nav-list > .nav-list-item:nth-child({{ activation_third_level_index }}){% endif %}{% endif %} {
+    > .nav-list-link {
+      display: block;
+      font-weight: 600;
+      text-decoration: none;
+      background-image: linear-gradient(
+        -90deg,
+        rgba($feedback-color, 1) 0%,
+        rgba($feedback-color, 0.8) 80%,
+        rgba($feedback-color, 0) 100%
+      );
+    }
+  }
+}
+
+// Styling for nav-list-expanders at first and second levels:
+{{ activation_collection_prefix }} {
+  > .nav-list-item:nth-child({{ activation_first_level_index }}){%- if activation_second_level_index %},
+  > .nav-list-item:nth-child({{ activation_first_level_index }}) > .nav-list > .nav-list-item:nth-child({{ activation_second_level_index }}){% endif %} {
+    > .nav-list-expander svg {
+      @if $nav-list-expander-right {
+        transform: rotate(-90deg);
+      } @else {
+        transform: rotate(90deg);
+      }
+    }
+
+    > .nav-list {
+      display: block;
+    }
+  }
+}
+
+// Styling for nav-list-expander for categories:
+.site-nav > .nav-category-list > .nav-list-item {
+  > .nav-list-expander svg {
+    @if $nav-list-expander-right {
+      transform: rotate(-90deg);
+    } @else {
+      transform: rotate(90deg);
+    }
+  }
+
+  > .nav-list {
+    display: block;
+  }
+}
+
+{%- endunless -%}
+{%- endunless -%}
+{%- endunless -%}
diff --git a/docs/_includes/css/callouts.scss.liquid b/docs/_includes/css/callouts.scss.liquid
new file mode 100644
index 0000000..e99600e
--- /dev/null
+++ b/docs/_includes/css/callouts.scss.liquid
@@ -0,0 +1,93 @@
+{%- comment -%}
+  {% include css/callouts.scss.liquid color_scheme = string %}
+  produces SCSS for all the callouts in site.callouts. For the "dark"
+  color scheme, the levels of the text and background colors are reversed.
+{%- endcomment -%}
+
+{%- assign callout_background_hue = "000" -%}
+{%- assign callout_color_hue = "300" -%}
+{%- if site.callouts_level == "loud" or include.color_scheme == "dark" and site.callouts_level != "quiet" -%}
+  {%- assign callout_background_hue = "300" -%}
+  {%- assign callout_color_hue = "000" -%}
+{%- endif -%}
+
+div.opaque {
+  background-color: $body-background-color;
+}
+
+{%- for callout in site.callouts %}
+
+{%- assign callout_opacity = callout[1].opacity | default: site.callouts_opacity | default: 0.2 -%}
+
+p.{{ callout[0] }}, blockquote.{{ callout[0] }} {
+    background: rgba(${{ callout[1].color }}-{{ callout_background_hue }}, {{ callout_opacity }});
+    border-left: $border-radius solid ${{ callout[1].color }}-{{ callout_color_hue }};
+    border-radius: $border-radius;
+    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08);
+    padding: .8rem;
+    {% if callout[1].title %}
+    &::before {
+        color: ${{ callout[1].color }}-{{ callout_color_hue }};
+        content: "{{ callout[1].title }}";
+        display: block;
+        font-weight: bold;
+        text-transform: uppercase;
+        font-size: .75em;
+        padding-bottom: .125rem;
+    }
+    {% endif %}
+    > .{{ callout[0] }}-title {
+      color: ${{ callout[1].color }}-{{ callout_color_hue }};
+      display: block;
+      font-weight: bold;
+      text-transform: uppercase;
+      font-size: .75em;
+      padding-bottom: .125rem;
+    }
+}
+
+p.{{ callout[0] }}-title, blockquote.{{ callout[0] }}-title {
+    background: rgba(${{ callout[1].color }}-{{ callout_background_hue }}, {{ callout_opacity }});
+    border-left: $border-radius solid ${{ callout[1].color }}-{{ callout_color_hue }};
+    border-radius: $border-radius;
+    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08);
+    padding: .8rem;
+    > p:first-child {
+      margin-top: 0;
+      margin-bottom: 0;
+      color: ${{ callout[1].color }}-{{ callout_color_hue }};
+      display: block;
+      font-weight: bold;
+      text-transform: uppercase;
+      font-size: .75em;
+      padding-bottom: .125rem;
+    }
+}
+
+blockquote.{{ callout[0] }} {
+  margin-left: 0;
+  margin-right: 0;
+  
+  > p:first-child {
+    margin-top: 0;
+  }
+    
+  > p:last-child {
+    margin-bottom: 0;
+  }
+}
+
+blockquote.{{ callout[0] }}-title {
+  margin-left: 0;
+  margin-right: 0;
+  
+  > p:nth-child(2) {
+    margin-top: 0;
+  }
+    
+  > p:last-child {
+    margin-bottom: 0;
+  }
+}
+
+{% endfor -%}
diff --git a/docs/_includes/css/custom.scss.liquid b/docs/_includes/css/custom.scss.liquid
new file mode 100644
index 0000000..2ad1576
--- /dev/null
+++ b/docs/_includes/css/custom.scss.liquid
@@ -0,0 +1,1 @@
+@import "./custom/custom";
diff --git a/docs/_includes/css/just-the-docs.scss.liquid b/docs/_includes/css/just-the-docs.scss.liquid
new file mode 100644
index 0000000..2eb480d
--- /dev/null
+++ b/docs/_includes/css/just-the-docs.scss.liquid
@@ -0,0 +1,12 @@
+{% if site.logo %}
+$logo: "{{ site.logo | relative_url }}";
+{% endif %}
+@import "./support/support";
+@import "./custom/setup";
+@import "./color_schemes/light";
+{% unless include.color_scheme == "light" %}
+@import "./color_schemes/{{ include.color_scheme }}";
+{% endunless %}
+@import "./modules";
+{% include css/callouts.scss.liquid color_scheme = include.color_scheme %}
+{% include css/custom.scss.liquid %}
diff --git a/docs/_includes/favicon.html b/docs/_includes/favicon.html
new file mode 100644
index 0000000..7d2a53d
--- /dev/null
+++ b/docs/_includes/favicon.html
@@ -0,0 +1,23 @@
+{%- comment -%}
+  Include as: {%- include_cached favicon.html -%}
+  Depends on: site.static_files.
+  Results in: HTML for a link to an existing `favicon.ico` file.
+  Overwrites: 
+    file.
+  
+  The endoflife.date site has 226 pages and 3410 static files. @marcwrobel pointed
+  out that the time taken by evaluating the code in this file on every page when
+  building that site was significant, and suggested making it optional. As it is
+  page-independent, it can easily be cached. Doing that reduced the time taken by
+  rendering `_includes/head.html` from 15.294s to 10.760s, thereby reducing the
+  total build time from 26.074s to 21.656s -- a saving of about 17%.
+{%- endcomment -%}
+
+{% for file in site.static_files %}
+  {% if file.path == site.favicon_ico or file.path == '/favicon.ico' %}
+    {% assign favicon = true %}
+  {% endif %}
+{% endfor %}
+{% if favicon %}
+  <link rel="icon" href="{{ site.favicon_ico | default: '/favicon.ico' | relative_url }}" type="image/x-icon">
+{% endif %}
diff --git a/docs/_includes/fix_linenos.html b/docs/_includes/fix_linenos.html
new file mode 100644
index 0000000..6243fb0
--- /dev/null
+++ b/docs/_includes/fix_linenos.html
@@ -0,0 +1,65 @@
+{%- comment -%}
+This file can be used to fix the HTML produced by Jekyll for highlighted
+code with line numbers.
+
+It works with `{% highlight some_language linenos %}...{% endhighlight %}`
+and with the Kramdown option to add line numbers to fenced code.
+
+The implementation was derived from the workaround provided by 
+Dmitry Hrabrov (DeXP) at
+https://github.com/penibelst/jekyll-compress-html/issues/71#issuecomment-188144901
+
+EXPLANATION
+
+The HTML produced by Rouge highlighting with lie numbers is of the form
+`code table`. Jekyll (<= 4.1.1) always wraps the highlighted HTML
+with `pre`. This wrapping is not only unnecessary, but also transforms
+the conforming HTML produced by Rouge to non-conforming HTML, which
+results in HTML validation error reports. 
+
+The fix removes the outer `pre` tags whenever they contain the pattern
+`<table class="rouge-table">`.
+  
+Apart from avoiding HTML validation errors, the fix allows the use of
+the [Jekyll layout for compressing HTML](http://jch.penibelst.de),
+which relies on `pre` tags not being nested, according to
+https://github.com/penibelst/jekyll-compress-html/issues/71#issuecomment-172069842 
+
+USAGE
+
+(Any names can be used for `some_var` and `some_language`.)
+
+{% capture some_var %}
+{% highlight some_language linenos %}
+Some code
+{% endhighlight %}
+{% endcapture %}
+{% include fix_linenos.html code=some_var %}
+
+For code fences:
+
+{% capture some_var %}
+```some_language
+Some code
+```
+{% endcapture %}
+{% assign some_var = some_var | markdownify %}
+{% include fix_linenos.html code=some_var %}
+
+CAVEATS
+
+The above does not work when `Some code` happens to contain the matched string 
+`<table class="rouge-table">`.
+
+The use of this file overwrites the variable `fix_linenos_code` with `nil`.
+
+{%- endcomment -%}
+
+{% assign fix_linenos_code = include.code %}
+{% if fix_linenos_code contains '<table class="rouge-table">' %}
+  {% assign fix_linenos_code = fix_linenos_code | replace: '<pre class="highlight">', '<pre>' %}
+  {% assign fix_linenos_code = fix_linenos_code | replace: "<pre><code", "<code" %}
+  {% assign fix_linenos_code = fix_linenos_code | replace: "</code></pre>", "</code>" %}
+{% endif %}
+{{ fix_linenos_code }}
+{% assign fix_linenos_code = nil %}
diff --git a/docs/_includes/footer_custom.html b/docs/_includes/footer_custom.html
new file mode 100644
index 0000000..64e08c2
--- /dev/null
+++ b/docs/_includes/footer_custom.html
@@ -0,0 +1,3 @@
+{%- if site.footer_content -%}
+  <p class="text-small text-grey-dk-100 mb-0">{{ site.footer_content }}</p>
+{%- endif -%}
diff --git a/docs/_includes/head.html b/docs/_includes/head.html
new file mode 100644
index 0000000..1ef8c0a
--- /dev/null
+++ b/docs/_includes/head.html
@@ -0,0 +1,49 @@
+{%- comment -%}
+  Include as: {%- include head.html -%}
+  Depends on: site.ga_tracking, site.ga_tracking_anonymize_ip,
+    site.search_enabled, site.static_files, site.favicon_ico.
+  Results in: HTML for the head element.
+  Includes:
+    head_nav.html, head_custom.html.
+  Overwrites: 
+    ga_tracking_ids, ga_property, file, favicon.
+  Should not be cached, because included files depend on page.
+{%- endcomment -%}
+
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
+
+  <link rel="stylesheet" href="{{ '/assets/css/just-the-docs-default.css' | relative_url }}">
+  
+  {% include head_nav.html %}
+
+  {% if site.ga_tracking != nil %}
+    {% assign ga_tracking_ids = site.ga_tracking | split: "," %}
+    <script async src="https://www.googletagmanager.com/gtag/js?id={{ ga_tracking_ids.first }}"></script>
+    <script>
+      window.dataLayer = window.dataLayer || [];
+      function gtag(){dataLayer.push(arguments);}
+      gtag('js', new Date());
+
+      {% for ga_property in ga_tracking_ids %}
+        gtag('config', '{{ ga_property }}'{% unless site.ga_tracking_anonymize_ip == nil %}, { 'anonymize_ip': true }{% endunless %});
+      {% endfor %}
+    </script>
+  {% endif %}
+
+  {% if site.search_enabled != false %}
+    <script src="{{ '/assets/js/vendor/lunr.min.js' | relative_url }}"></script>
+  {% endif %}
+
+  <script src="{{ '/assets/js/just-the-docs.js' | relative_url }}"></script>
+
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+
+  {% include_cached favicon.html %}
+
+  {% seo %}
+
+  {% include head_custom.html %}
+
+</head>
diff --git a/docs/_includes/head_custom.html b/docs/_includes/head_custom.html
new file mode 100644
index 0000000..e69de29
diff --git a/docs/_includes/head_nav.html b/docs/_includes/head_nav.html
new file mode 100644
index 0000000..00ad569
--- /dev/null
+++ b/docs/_includes/head_nav.html
@@ -0,0 +1,48 @@
+{%- comment -%}
+  Include as: {%- include head_nav.html -%}
+  Depends on: site.color_scheme.
+  Results in: HTML for a page-specific style element.
+  Includes:
+    css/activation.scss.liquid.
+  Overwrites: 
+    activation, test_scss, scss, css, index, count.
+  Should not be cached, because css/activation.scss.liquid depends on page.
+{%- endcomment -%}
+
+{% capture activation %}
+  {% include css/activation.scss.liquid %}
+{%- endcapture -%}
+
+{% capture test_scss %}
+  @import "./support/support";
+  @import "./color_schemes/light";
+  {{ activation }}
+{%- endcapture -%}
+
+{%- capture scss -%}
+  @import "./support/support";
+  @import "./custom/setup";
+  {% if site.color_scheme and site.color_scheme != "nil" -%}
+    {%- assign color_scheme = site.color_scheme -%}
+  {%- else -%}
+    {%- assign color_scheme = "light" -%}
+  {%- endif %}
+  @import "./color_schemes/light";
+  {% unless color_scheme == "light" %}
+  @import "./color_schemes/{{ color_scheme }}";
+  {% endunless %}
+  {{ activation }}
+{%- endcapture -%}
+
+{%- comment -%}
+  Convert to CSS, then remove the color_scheme import rules to avoid duplication.
+  The value of count is page-dependent, but independent of custom color schemes.
+{%- endcomment -%}
+{%- assign count = test_scss  | scssify | split: ".site-nav" | size -%}
+{%- unless count == 1 %}
+{%- assign index = 1 | minus: count -%}
+{%- assign css = scss | scssify | split: ".site-nav" | slice: index, count | join: ".site-nav" -%}
+<style type="text/css">
+{{ css | prepend: ".site-nav" }}
+</style>
+{%- endunless %}
diff --git a/docs/_includes/header_custom.html b/docs/_includes/header_custom.html
new file mode 100644
index 0000000..e69de29
diff --git a/docs/_includes/icons/code_copy.html b/docs/_includes/icons/code_copy.html
new file mode 100644
index 0000000..fb6421f
--- /dev/null
+++ b/docs/_includes/icons/code_copy.html
@@ -0,0 +1,15 @@
+<!-- Bootstrap Icons. MIT License: https://github.com/twbs/icons/blob/main/LICENSE.md -->
+<symbol id="svg-copy" viewBox="0 0 16 16">
+  <title>Copy</title>
+  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16">
+    <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/>
+    <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/>
+  </svg>
+</symbol>
+<symbol id="svg-copied" viewBox="0 0 16 16">
+  <title>Copied</title>
+  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check-fill" viewBox="0 0 16 16">
+    <path d="M6.5 0A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3Zm3 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3Z"/>
+    <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1A2.5 2.5 0 0 1 9.5 5h-3A2.5 2.5 0 0 1 4 2.5v-1Zm6.854 7.354-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 0 1 .708-.708L7.5 10.793l2.646-2.647a.5.5 0 0 1 .708.708Z"/>
+  </svg>
+</symbol>
diff --git a/docs/_includes/icons/document.html b/docs/_includes/icons/document.html
new file mode 100644
index 0000000..c09e8a5
--- /dev/null
+++ b/docs/_includes/icons/document.html
@@ -0,0 +1,6 @@
+<symbol id="svg-doc" viewBox="0 0 24 24">
+  <title>Document</title>
+  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file">
+    <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline>
+  </svg>
+</symbol>
diff --git a/docs/_includes/icons/expand.html b/docs/_includes/icons/expand.html
new file mode 100644
index 0000000..79921a5
--- /dev/null
+++ b/docs/_includes/icons/expand.html
@@ -0,0 +1,6 @@
+<symbol id="svg-arrow-right" viewBox="0 0 24 24">
+  <title>Expand</title>
+  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right">
+    <polyline points="9 18 15 12 9 6"></polyline>
+  </svg>
+</symbol>
diff --git a/docs/_includes/icons/external_link.html b/docs/_includes/icons/external_link.html
new file mode 100644
index 0000000..1592be6
--- /dev/null
+++ b/docs/_includes/icons/external_link.html
@@ -0,0 +1,5 @@
+<!-- Feather. MIT License: https://github.com/feathericons/feather/blob/master/LICENSE -->
+<symbol id="svg-external-link" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link">
+  <title id="svg-external-link-title">(external link)</title>
+  <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line>
+</symbol>
diff --git a/docs/_includes/icons/icons.html b/docs/_includes/icons/icons.html
new file mode 100644
index 0000000..007a495
--- /dev/null
+++ b/docs/_includes/icons/icons.html
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
+  {% include icons/link.html %}
+  {% include icons/menu.html %}
+  {% include icons/expand.html %}
+  {% include icons/external_link.html %}
+  {% if site.search_enabled != false %}
+    {% include icons/document.html %}
+    {% include icons/search.html %}
+  {% endif %}
+  {% if site.enable_copy_code_button != false %}
+    {% include icons/code_copy.html %}
+  {% endif %}
+</svg>
diff --git a/docs/_includes/icons/link.html b/docs/_includes/icons/link.html
new file mode 100644
index 0000000..de24be7
--- /dev/null
+++ b/docs/_includes/icons/link.html
@@ -0,0 +1,6 @@
+<symbol id="svg-link" viewBox="0 0 24 24">
+  <title>Link</title>
+  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link">
+    <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
+  </svg>
+</symbol>
diff --git a/docs/_includes/icons/menu.html b/docs/_includes/icons/menu.html
new file mode 100644
index 0000000..d256575
--- /dev/null
+++ b/docs/_includes/icons/menu.html
@@ -0,0 +1,6 @@
+<symbol id="svg-menu" viewBox="0 0 24 24">
+  <title>Menu</title>
+  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu">
+    <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line>
+  </svg>
+</symbol>
diff --git a/docs/_includes/icons/search.html b/docs/_includes/icons/search.html
new file mode 100644
index 0000000..8f72c6a
--- /dev/null
+++ b/docs/_includes/icons/search.html
@@ -0,0 +1,6 @@
+<symbol id="svg-search" viewBox="0 0 24 24">
+  <title>Search</title>
+  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search">
+    <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line>
+  </svg>
+</symbol>
diff --git a/docs/_includes/js/custom.js b/docs/_includes/js/custom.js
new file mode 100644
index 0000000..e69de29
diff --git a/docs/_includes/lunr/custom-data.json b/docs/_includes/lunr/custom-data.json
new file mode 100644
index 0000000..e69de29
diff --git a/docs/_includes/lunr/custom-index.js b/docs/_includes/lunr/custom-index.js
new file mode 100644
index 0000000..e69de29
diff --git a/docs/_includes/mermaid_config.js b/docs/_includes/mermaid_config.js
new file mode 100644
index 0000000..4b42f37
--- /dev/null
+++ b/docs/_includes/mermaid_config.js
@@ -0,0 +1,4 @@
+// _includes/mermaid_config.js
+{
+    theme: "forest"
+}
\ No newline at end of file
diff --git a/docs/_includes/nav.html b/docs/_includes/nav.html
new file mode 100644
index 0000000..0b20b36
--- /dev/null
+++ b/docs/_includes/nav.html
@@ -0,0 +1,75 @@
+{%- comment -%}
+  Include as: {%- include_cached nav.html pages=pages -%}
+  Depends on: include.pages.
+  Results in: HTML for the navigation panel.
+  Includes:
+    sorted_pages.html
+  Overwrites:
+    nav_pages, first_level_pages, second_level_pages, third_level_pages,
+    node, children_list, child, grand_children_list, grand_child.
+{%- endcomment -%}
+
+{%- assign nav_pages = include.pages
+    | where_exp: "item", "item.title != nil"
+    | where_exp: "item", "item.nav_exclude != true" -%}
+
+{%- include sorted_pages.html pages = nav_pages -%}
+
+{%- comment -%}
+  It might be more efficient to sort the pages at each level separately.
+{%- endcomment -%}
+
+{%- assign first_level_pages = sorted_pages
+    | where_exp: "item", "item.parent == nil" -%}
+{%- assign second_level_pages = sorted_pages
+    | where_exp: "item", "item.parent != nil"
+    | where_exp: "item", "item.grand_parent == nil" -%}
+{%- assign third_level_pages = sorted_pages
+    | where_exp: "item", "item.grand_parent != nil" -%}
+
+<ul class="nav-list">
+{%- for node in first_level_pages -%}
+  <li class="nav-list-item">
+    {%- if node.has_children -%}
+    <button class="nav-list-expander btn-reset" aria-label="toggle items in {{ node.title }} category" aria-pressed="false">
+      <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg>
+    </button>
+    {%- endif -%}
+    <a href="{{ node.url | relative_url }}" class="nav-list-link">{{ node.title }}</a>
+    {%- if node.has_children -%}
+      {%- assign children_list = second_level_pages
+            | where: "parent", node.title -%}
+      {%- if node.child_nav_order == 'desc' or node.child_nav_order == 'reversed' -%}
+        {%- assign children_list = children_list | reverse -%}
+      {%- endif -%}
+      <ul class="nav-list">
+      {%- for child in children_list -%}
+        <li class="nav-list-item">
+          {%- if child.has_children -%}
+          <button class="nav-list-expander btn-reset" aria-label="toggle items in {{ child.title }} category" aria-pressed="false">
+            <svg viewBox="0 0 24 24" aria-hidden="true"><use xlink:href="#svg-arrow-right"></use></svg>
+          </button>
+          {%- endif -%}
+          <a href="{{ child.url | relative_url }}" class="nav-list-link">{{ child.title }}</a>
+          {%- if child.has_children -%}
+            {%- assign grand_children_list = third_level_pages
+                  | where: "parent", child.title
+                  | where: "grand_parent", node.title -%}
+            {%- if child.child_nav_order == 'desc' or child.child_nav_order == 'reversed' -%}
+              {%- assign grand_children_list = grand_children_list | reverse -%}
+            {%- endif -%}
+            <ul class="nav-list">
+            {%- for grand_child in grand_children_list -%}
+              <li class="nav-list-item">
+                <a href="{{ grand_child.url | relative_url }}" class="nav-list-link">{{ grand_child.title }}</a>
+              </li>
+            {%- endfor -%}
+            </ul>
+          {%- endif -%}
+        </li>
+      {%- endfor -%}
+      </ul>
+    {%- endif -%}
+  </li>
+{%- endfor -%}
+</ul>
diff --git a/docs/_includes/nav_footer_custom.html b/docs/_includes/nav_footer_custom.html
new file mode 100644
index 0000000..e69de29
diff --git a/docs/_includes/search_placeholder_custom.html b/docs/_includes/search_placeholder_custom.html
new file mode 100644
index 0000000..2885058
--- /dev/null
+++ b/docs/_includes/search_placeholder_custom.html
@@ -0,0 +1,1 @@
+Search {{site.title}}
diff --git a/docs/_includes/sorted_pages.html b/docs/_includes/sorted_pages.html
new file mode 100644
index 0000000..659be10
--- /dev/null
+++ b/docs/_includes/sorted_pages.html
@@ -0,0 +1,109 @@
+{%- comment -%}
+  Include as: {%- include sorted_pages.html pages=array_of_pages -%}
+  Depends on: include.pages.
+  Assigns to: sorted_pages.
+  Overwrites: 
+    nav_order_pages, title_order_pages, double_quote, empty_array,
+    nav_number_pages, nav_string_pages, nav_order_groups, group,
+    title_number_pages, title_string_pages, title_order_groups.
+{%- endcomment -%}
+
+{%- comment -%}
+  The `nav_order` values of pages affect the order in which they are shown in
+  the navigation panel and in the automatically generated tables of contents.
+  Sibling pages with the same `nav_order` value may be shown in any order.
+  Sibling pages with no `nav_order` value are shown after all pages that have
+  explicit `nav_order` values, ordered by their `title` values.
+  
+  The `nav_order` and `title` values can be numbers or strings. To avoid build
+  failures, we sort numbers and strings separately. We sort numbers by their
+  values, and strings lexicographically. The case-sensitivity of string sorting
+  is determined by the configuration setting of `nav_sort`. Pages with no `title`
+  value are excluded from the navigation.
+
+  Note: Numbers used as `title` or `nav_order` values should not be in quotes,
+  unless you intend them to be lexicographically ordered. Numbers are written
+  without spaces or thousands-separators. Negative numbers are preceded by `-`.
+  Floats are written with the integral and fractional parts separated by `.`.
+  (Bounds on the magnitude and precision are presumably the same as in Liquid.)
+{%- endcomment -%}
+
+{%- assign nav_order_pages = include.pages
+      | where_exp: "item", "item.nav_order != nil" -%}
+{%- assign title_order_pages = include.pages
+      | where_exp: "item", "item.nav_order == nil" -%}
+
+{%- comment -%}
+  First, filter `nav_order_pages` and `title_order_pages` according to the type
+  of value to be used for sorting.
+  
+  The first character of the result of filtering with `jsonify` is `"` only for
+  strings. Removing `"` from its `slice : 0` has size 0 for strings and 1 for
+  numbers, so grouping the pages gives at most two groups.
+{%- endcomment -%}
+
+{%- assign double_quote = '"' -%}
+{%- assign empty_array = "" | split: "" -%}
+
+{%- assign nav_string_pages = empty_array -%}
+{%- assign nav_number_pages = empty_array -%}
+{%- unless nav_order_pages == empty -%}
+  {%- assign nav_order_groups = nav_order_pages
+        | group_by_exp: "item",
+            "item.nav_order | jsonify | slice: 0 | remove: double_quote | size" -%}
+  {%- for group in nav_order_groups -%}
+    {%- if group.name == 0 -%}
+      {%- assign nav_string_pages = group.items -%}
+    {%- elsif group.name == 1 -%}
+      {%- assign nav_number_pages = group.items -%}
+    {%- endif -%}
+  {%- endfor -%}
+{%- endunless -%}
+
+{%- assign title_string_pages = empty_array -%}
+{%- assign title_number_pages = empty_array -%}
+{%- unless title_order_pages == empty -%}
+  {%- assign title_order_groups = title_order_pages
+        | group_by_exp: "item",
+            "item.title | jsonify | slice: 0 | remove: double_quote | size" -%}
+  {%- for group in title_order_groups -%}
+    {%- if group.name == 0 -%}
+      {%- assign title_string_pages = group.items -%}
+    {%- elsif group.name == 1 -%}
+      {%- assign title_number_pages = group.items -%}
+    {%- endif -%}
+  {%- endfor -%}
+{%- endunless -%}
+
+{%- comment -%}
+  Now sort each array of pages separately, then concatenate the sorted arrays.
+{%- endcomment -%}
+
+{%- unless nav_number_pages == empty -%}
+  {%- assign nav_number_pages = nav_number_pages | sort: "nav_order" -%}
+{%- endunless -%}
+
+{%- unless nav_string_pages == empty -%}
+  {%- if site.nav_sort == 'case_insensitive' -%}
+    {%- assign nav_string_pages = nav_string_pages | sort_natural: "nav_order" -%}
+  {%- else -%}
+    {%- assign nav_string_pages = nav_string_pages | sort: "nav_order" -%}
+  {%- endif -%}
+{%- endunless -%}
+
+{%- unless title_number_pages == empty -%}
+  {%- assign title_number_pages = title_number_pages | sort: "title" -%}
+{%- endunless -%}
+
+{%- unless title_string_pages == empty -%}
+  {%- if site.nav_sort == 'case_insensitive' -%}
+    {%- assign title_string_pages = title_string_pages | sort_natural: "title" -%}
+  {%- else -%}
+    {%- assign title_string_pages = title_string_pages | sort: "title" -%}
+  {%- endif -%}
+{%- endunless -%}
+
+{%- assign sorted_pages = nav_number_pages
+      | concat: nav_string_pages
+      | concat: title_number_pages
+      | concat: title_string_pages -%}
diff --git a/docs/_includes/title.html b/docs/_includes/title.html
new file mode 100644
index 0000000..8f65336
--- /dev/null
+++ b/docs/_includes/title.html
@@ -0,0 +1,5 @@
+{% if site.logo %}
+  <div class="site-logo" role="img" aria-label="{{ site.title }}"></div>
+{% else %}
+  {{ site.title }}
+{% endif %}
diff --git a/docs/_includes/toc.html b/docs/_includes/toc.html
new file mode 100644
index 0000000..7914411
--- /dev/null
+++ b/docs/_includes/toc.html
@@ -0,0 +1,5 @@
+<nav>
+    <h4>Table of Contents</h4>
+    * this unordered seed list will be replaced by toc as unordered list
+    {:toc}
+  </nav>
\ No newline at end of file
diff --git a/docs/_includes/toc_heading_custom.html b/docs/_includes/toc_heading_custom.html
new file mode 100644
index 0000000..82a7700
--- /dev/null
+++ b/docs/_includes/toc_heading_custom.html
@@ -0,0 +1,1 @@
+<h2 class="text-delta">Table of contents</h2>
diff --git a/docs/_includes/vendor/anchor_headings.html b/docs/_includes/vendor/anchor_headings.html
new file mode 100755
index 0000000..36b8470
--- /dev/null
+++ b/docs/_includes/vendor/anchor_headings.html
@@ -0,0 +1,172 @@
+{% capture headingsWorkspace %}
+  {% comment %}
+    Copyright (c) 2018 Vladimir "allejo" Jimenez
+
+    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.
+  {% endcomment %}
+  {% comment %}
+    Version 1.0.12
+      https://github.com/allejo/jekyll-anchor-headings
+
+    "Be the pull request you wish to see in the world." ~Ben Balter
+
+    Usage:
+      {% include anchor_headings.html html=content anchorBody="#" %}
+
+    Parameters:
+      * html          (string) - the HTML of compiled markdown generated by kramdown in Jekyll
+
+    Optional Parameters:
+      * beforeHeading (bool)   : false  - Set to true if the anchor should be placed _before_ the heading's content
+      * headerAttrs   (string) :  ''    - Any custom HTML attributes that will be added to the heading tag; you may NOT use `id`;
+                                          the `%heading%` and `%html_id%` placeholders are available
+      * anchorAttrs   (string) :  ''    - Any custom HTML attributes that will be added to the `<a>` tag; you may NOT use `href`, `class` or `title`;
+                                          the `%heading%` and `%html_id%` placeholders are available
+      * anchorBody    (string) :  ''    - The content that will be placed inside the anchor; the `%heading%` placeholder is available
+      * anchorClass   (string) :  ''    - The class(es) that will be used for each anchor. Separate multiple classes with a space
+      * anchorTitle   (string) :  ''    - The `title` attribute that will be used for anchors
+      * h_min         (int)    :  1     - The minimum header level to build an anchor for; any header lower than this value will be ignored
+      * h_max         (int)    :  6     - The maximum header level to build an anchor for; any header greater than this value will be ignored
+      * bodyPrefix    (string) :  ''    - Anything that should be inserted inside of the heading tag _before_ its anchor and content
+      * bodySuffix    (string) :  ''    - Anything that should be inserted inside of the heading tag _after_ its anchor and content
+      * generateId    (true)   :  false - Set to true if a header without id should generate an id to use.
+
+    Output:
+      The original HTML with the addition of anchors inside of all of the h1-h6 headings.
+  {% endcomment %}
+
+  {% assign minHeader = include.h_min | default: 1 %}
+  {% assign maxHeader = include.h_max | default: 6 %}
+  {% assign beforeHeading = include.beforeHeading %}
+  {% assign headerAttrs = include.headerAttrs %}
+  {% assign nodes = include.html | split: '<h' %}
+
+  {% capture edited_headings %}{% endcapture %}
+
+  {% for _node in nodes %}
+    {% capture node %}{{ _node | strip }}{% endcapture %}
+
+    {% if node == "" %}
+      {% continue %}
+    {% endif %}
+
+    {% assign nextChar = node | replace: '"', '' | strip | slice: 0, 1 %}
+    {% assign headerLevel = nextChar | times: 1 %}
+
+    <!-- If the level is cast to 0, it means it's not a h1-h6 tag, so let's see if we need to fix it -->
+    {% if headerLevel == 0 %}
+      <!-- Split up the node based on closing angle brackets and get the first one. -->
+      {% assign firstChunk = node | split: '>' | first %}
+
+      <!-- If the first chunk does NOT contain a '<', that means we've broken another HTML tag that starts with 'h' -->
+      {% unless firstChunk contains '<' %}
+        {% capture node %}<h{{ node }}{% endcapture %}
+      {% endunless %}
+
+      {% capture edited_headings %}{{ edited_headings }}{{ node }}{% endcapture %}
+      {% continue %}
+    {% endif %}
+
+    {% capture _closingTag %}</h{{ headerLevel }}>{% endcapture %}
+    {% assign _workspace = node | split: _closingTag %}
+    {% capture _hAttrToStrip %}{{ _workspace[0] | split: '>' | first }}>{% endcapture %}
+    {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %}
+    {% assign escaped_header = header | strip_html | strip %}
+
+    {% assign _classWorkspace = _workspace[0] | split: 'class="' %}
+    {% assign _classWorkspace = _classWorkspace[1] | split: '"' %}
+    {% assign _html_class = _classWorkspace[0] %}
+
+    {% if _html_class contains "no_anchor" %}
+      {% assign skip_anchor = true %}
+    {% else %}
+      {% assign skip_anchor = false %}
+    {% endif %}
+
+    {% assign _idWorkspace = _workspace[0] | split: 'id="' %}
+    {% if _idWorkspace[1] %}
+      {% assign _idWorkspace = _idWorkspace[1] | split: '"' %}
+      {% assign html_id = _idWorkspace[0] %}
+    {% elsif include.generateId %}
+      <!-- If the header did not have an id we create one. -->
+      {% assign html_id = escaped_header | slugify %}
+      {% if html_id == "" %}
+        {% assign html_id = false %}
+      {% endif %}
+      {% capture headerAttrs %}{{ headerAttrs }} id="%html_id%"{% endcapture %}
+    {% endif %}
+
+    <!-- Build the anchor to inject for our heading -->
+    {% capture anchor %}{% endcapture %}
+
+    {% if skip_anchor == false and html_id and headerLevel >= minHeader and headerLevel <= maxHeader %}
+      {% if headerAttrs %}
+        {% capture _hAttrToStrip %}{{ _hAttrToStrip | split: '>' | first }} {{ headerAttrs | replace: '%heading%', escaped_header | replace: '%html_id%', html_id }}>{% endcapture %}
+      {% endif %}
+
+      {% capture anchor %}href="#{{ html_id }}"{% endcapture %}
+
+      {% if include.anchorClass %}
+        {% capture anchor %}{{ anchor }} class="{{ include.anchorClass }}"{% endcapture %}
+      {% endif %}
+
+      {% if include.anchorTitle %}
+        {% capture anchor %}{{ anchor }} title="{{ include.anchorTitle | replace: '%heading%', escaped_header }}"{% endcapture %}
+      {% endif %}
+
+      {% if include.anchorAttrs %}
+        {% capture anchor %}{{ anchor }} {{ include.anchorAttrs | replace: '%heading%', escaped_header | replace: '%html_id%', html_id }}{% endcapture %}
+      {% endif %}
+
+      {% capture anchor %}<a {{ anchor }}>{{ include.anchorBody | replace: '%heading%', escaped_header | default: '' }}</a>{% endcapture %}
+
+      <!-- In order to prevent adding extra space after a heading, we'll let the 'anchor' value contain it -->
+      {% if beforeHeading %}
+        {% capture anchor %}{{ anchor }} {% endcapture %}
+      {% else %}
+        {% capture anchor %} {{ anchor }}{% endcapture %}
+      {% endif %}
+    {% endif %}
+
+    {% capture new_heading %}
+<h{{ _hAttrToStrip }}
+  {{ include.bodyPrefix }}
+  {% if beforeHeading %}
+    {{ anchor }}{{ header }}
+  {% else %}
+    {{ header }}{{ anchor }}
+  {% endif %}
+  {{ include.bodySuffix }}
+</h{{ headerLevel }}>
+    {% endcapture %}
+
+    <!--
+    If we have content after the `</hX>` tag, then we'll want to append that here so we don't lost any content.
+    -->
+    {% assign chunkCount = _workspace | size %}
+    {% if chunkCount > 1 %}
+      {% capture new_heading %}{{ new_heading }}{{ _workspace | last }}{% endcapture %}
+    {% endif %}
+
+    {% capture edited_headings %}{{ edited_headings }}{{ new_heading }}{% endcapture %}
+  {% endfor %}
+{% endcapture %}{% assign headingsWorkspace = '' %}{{ edited_headings | strip }}
diff --git a/docs/_layouts/about.html b/docs/_layouts/about.html
new file mode 100644
index 0000000..5e71126
--- /dev/null
+++ b/docs/_layouts/about.html
@@ -0,0 +1,5 @@
+---
+layout: default
+---
+
+{{ content }}
diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html
new file mode 100644
index 0000000..923c1c1
--- /dev/null
+++ b/docs/_layouts/default.html
@@ -0,0 +1,41 @@
+---
+layout: table_wrappers
+---
+
+<!DOCTYPE html>
+
+<html lang="{{ site.lang | default: 'en-US' }}">
+{% include head.html %}
+<body>
+  <a class="skip-to-main" href="#main-content">Skip to main content</a>
+  {% include icons/icons.html %}
+  {% include components/sidebar.html %}
+  <div class="main" id="top">
+    {% include components/header.html %}
+    <div class="main-content-wrap">
+      {% include components/breadcrumbs.html %}
+      <div id="main-content" class="main-content">
+        <main>
+          {% if site.heading_anchors != false %}
+            {% include vendor/anchor_headings.html html=content beforeHeading="true" anchorBody="<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><use xlink:href=\"#svg-link\"></use></svg>" anchorClass="anchor-heading" anchorAttrs="aria-labelledby=\"%html_id%\"" %}
+          {% else %}
+            {{ content }}
+          {% endif %}
+
+          {% if page.has_children == true and page.has_toc != false %}
+            {% include components/children_nav.html %}
+          {% endif %}
+        </main>
+        {% include components/footer.html %}
+      </div>
+    </div>
+    {% if site.search_enabled != false %}
+      {% include components/search_footer.html %}
+    {% endif %}
+  </div>
+
+  {% if site.mermaid %}
+    {% include components/mermaid.html %}
+  {% endif %}
+</body>
+</html>
diff --git a/docs/_layouts/home.html b/docs/_layouts/home.html
new file mode 100644
index 0000000..5e71126
--- /dev/null
+++ b/docs/_layouts/home.html
@@ -0,0 +1,5 @@
+---
+layout: default
+---
+
+{{ content }}
diff --git a/docs/_layouts/minimal.html b/docs/_layouts/minimal.html
new file mode 100644
index 0000000..b12c5db
--- /dev/null
+++ b/docs/_layouts/minimal.html
@@ -0,0 +1,34 @@
+---
+layout: table_wrappers
+---
+
+<!DOCTYPE html>
+
+<html lang="{{ site.lang | default: 'en-US' }}">
+{% include head.html %}
+<body>
+  <a class="skip-to-main" href="#main-content">Skip to main content</a>
+  {% include icons/icons.html %}
+  <div class="main-content-wrap" id="top">
+    {% include components/breadcrumbs.html %}
+    <div id="main-content" class="main-content" role="main">
+      {% if site.heading_anchors != false %}
+        {% include vendor/anchor_headings.html html=content beforeHeading="true" anchorBody="<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><use xlink:href=\"#svg-link\"></use></svg>" anchorClass="anchor-heading" anchorAttrs="aria-labelledby=\"%html_id%\"" %}
+      {% else %}
+        {{ content }}
+      {% endif %}
+
+      {% if page.has_children == true and page.has_toc != false %}
+        {% include components/children_nav.html %}
+      {% endif %}
+
+      {% include components/footer.html %}
+
+    </div>
+  </div>
+
+  {% if site.mermaid %}
+    {% include components/mermaid.html %}
+  {% endif %}
+</body>
+</html>
diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html
new file mode 100644
index 0000000..5e71126
--- /dev/null
+++ b/docs/_layouts/page.html
@@ -0,0 +1,5 @@
+---
+layout: default
+---
+
+{{ content }}
diff --git a/docs/_layouts/post.html b/docs/_layouts/post.html
new file mode 100644
index 0000000..5e71126
--- /dev/null
+++ b/docs/_layouts/post.html
@@ -0,0 +1,5 @@
+---
+layout: default
+---
+
+{{ content }}
diff --git a/docs/_layouts/table_wrappers.html b/docs/_layouts/table_wrappers.html
new file mode 100644
index 0000000..3f8f226
--- /dev/null
+++ b/docs/_layouts/table_wrappers.html
@@ -0,0 +1,7 @@
+---
+layout: vendor/compress
+---
+
+{% assign content_ = content | replace: '<table', '<div class="table-wrapper"><table' %}
+{% assign content_ = content_ | replace: '</table>', '</table></div>' %}
+{{ content_ }}
diff --git a/docs/_layouts/vendor/compress.html b/docs/_layouts/vendor/compress.html
new file mode 100644
index 0000000..bb34487
--- /dev/null
+++ b/docs/_layouts/vendor/compress.html
@@ -0,0 +1,10 @@
+---
+# Jekyll layout that compresses HTML
+# v3.1.0
+# http://jch.penibelst.de/
+# © 2014–2015 Anatol Broder
+# MIT License
+---
+
+{% capture _LINE_FEED %}
+{% endcapture %}{% if site.compress_html.ignore.envs contains jekyll.environment or site.compress_html.ignore.envs == "all" %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% assign _profile = site.compress_html.profile %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}</{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if _profile and _endings %}{% assign _profile_endings = _content | size | plus: 1 %}{% endif %}{% for _element in site.compress_html.startings %}{% capture _start %}<{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _start %}{% endfor %}{% if _profile and site.compress_html.startings %}{% assign _profile_startings = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.comments == "all" %}{% assign _comments = "<!-- -->" | split: " " %}{% else %}{% assign _comments = site.compress_html.comments %}{% endif %}{% if _comments.size == 2 %}{% capture _comment_befores %}.{{ _content }}{% endcapture %}{% assign _comment_befores = _comment_befores | split: _comments.first %}{% for _comment_before in _comment_befores %}{% if forloop.first %}{% continue %}{% endif %}{% capture _comment_outside %}{% if _carry %}{{ _comments.first }}{% endif %}{{ _comment_before }}{% endcapture %}{% capture _comment %}{% unless _carry %}{{ _comments.first }}{% endunless %}{{ _comment_outside | split: _comments.last | first }}{% if _comment_outside contains _comments.last %}{{ _comments.last }}{% assign _carry = false %}{% else %}{% assign _carry = true %}{% endif %}{% endcapture %}{% assign _content = _content | remove_first: _comment %}{% endfor %}{% if _profile %}{% assign _profile_comments = _content | size | plus: 1 %}{% endif %}{% endif %}{% assign _pre_befores = _content | split: "<pre" %}{% assign _content = "" %}{% for _pre_before in _pre_befores %}{% assign _pres = _pre_before | split: "</pre>" %}{% assign _pres_after = "" %}{% if _pres.size != 0 %}{% if site.compress_html.blanklines %}{% assign _lines = _pres.last | split: _LINE_FEED %}{% capture _pres_after %}{% for _line in _lines %}{% assign _trimmed = _line | split: " " | join: " " %}{% if _trimmed != empty or forloop.last %}{% unless forloop.first %}{{ _LINE_FEED }}{% endunless %}{{ _line }}{% endif %}{% endfor %}{% endcapture %}{% else %}{% assign _pres_after = _pres.last | split: " " | join: " " %}{% endif %}{% endif %}{% capture _content %}{{ _content }}{% if _pre_before contains "</pre>" %}<pre{{ _pres.first }}</pre>{% endif %}{% unless _pre_before contains "</pre>" and _pres.size == 1 %}{{ _pres_after }}{% endunless %}{% endcapture %}{% endfor %}{% if _profile %}{% assign _profile_collapse = _content | size | plus: 1 %}{% endif %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " <e;<e; </e>;</e>;</e> ;</e>" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{% if _profile and _clippings %}{% assign _profile_clippings = _content | size | plus: 1 %}{% endif %}{{ _content }}{% if _profile %} <table id="compress_html_profile_{{ site.time | date: "%Y%m%d" }}" class="compress_html_profile"> <thead> <tr> <td>Step <td>Bytes <tbody> <tr> <td>raw <td>{{ content | size }}{% if _profile_endings %} <tr> <td>endings <td>{{ _profile_endings }}{% endif %}{% if _profile_startings %} <tr> <td>startings <td>{{ _profile_startings }}{% endif %}{% if _profile_comments %} <tr> <td>comments <td>{{ _profile_comments }}{% endif %}{% if _profile_collapse %} <tr> <td>collapse <td>{{ _profile_collapse }}{% endif %}{% if _profile_clippings %} <tr> <td>clippings <td>{{ _profile_clippings }}{% endif %} </table>{% endif %}{% endif %}
diff --git a/docs/_sass/base.scss b/docs/_sass/base.scss
new file mode 100644
index 0000000..0068d71
--- /dev/null
+++ b/docs/_sass/base.scss
@@ -0,0 +1,113 @@
+// Base element style overrides
+// stylelint-disable selector-no-type, selector-max-type, selector-max-specificity, selector-max-id
+
+:root {
+  color-scheme: $color-scheme;
+}
+
+* {
+  box-sizing: border-box;
+}
+
+html {
+  @include fs-4;
+
+  scroll-behavior: smooth;
+}
+
+body {
+  font-family: $body-font-family;
+  font-size: inherit;
+  line-height: $body-line-height;
+  color: $body-text-color;
+  background-color: $body-background-color;
+  overflow-wrap: break-word;
+}
+
+ol,
+ul,
+dl,
+pre,
+address,
+blockquote,
+table,
+div,
+hr,
+form,
+fieldset,
+noscript .table-wrapper {
+  margin-top: 0;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+#toctitle {
+  margin-top: 0;
+  margin-bottom: 1em;
+  font-weight: 500;
+  line-height: $body-heading-line-height;
+  color: $body-heading-color;
+}
+
+p {
+  margin-top: 1em;
+  margin-bottom: 1em;
+}
+
+a {
+  color: $link-color;
+  text-decoration: none;
+}
+
+a:not([class]) {
+  text-decoration: underline;
+  text-decoration-color: $border-color;
+  text-underline-offset: 2px;
+
+  &:hover {
+    text-decoration-color: rgba($link-color, 0.45);
+  }
+}
+
+code {
+  font-family: $mono-font-family;
+  font-size: 0.75em;
+  line-height: $body-line-height;
+}
+
+figure,
+pre {
+  margin: 0;
+}
+
+li {
+  margin: 0.25em 0;
+}
+
+img {
+  max-width: 100%;
+  height: auto;
+}
+
+hr {
+  height: 1px;
+  padding: 0;
+  margin: $sp-6 0;
+  background-color: $border-color;
+  border: 0;
+}
+
+// adds a GitHub-style sidebar to blockquotes
+blockquote {
+  margin: 10px 0;
+
+  // resets user-agent stylesheets for blockquotes
+  margin-block-start: 0;
+  margin-inline-start: 0;
+  padding-left: 1rem;
+  border-left: 3px solid $border-color;
+}
diff --git a/docs/_sass/buttons.scss b/docs/_sass/buttons.scss
new file mode 100644
index 0000000..7953f7f
--- /dev/null
+++ b/docs/_sass/buttons.scss
@@ -0,0 +1,127 @@
+// Buttons and things that look like buttons
+// stylelint-disable color-named
+
+.btn {
+  display: inline-block;
+  box-sizing: border-box;
+  padding: 0.3em 1em;
+  margin: 0;
+  font-family: inherit;
+  font-size: inherit;
+  font-weight: 500;
+  line-height: 1.5;
+  color: $link-color;
+  text-decoration: none;
+  vertical-align: baseline;
+  cursor: pointer;
+  background-color: $base-button-color;
+  border-width: 0;
+  border-radius: $border-radius;
+  box-shadow:
+    0 1px 2px rgba(0, 0, 0, 0.12),
+    0 3px 10px rgba(0, 0, 0, 0.08);
+  appearance: none;
+
+  &:focus {
+    text-decoration: none;
+    outline: none;
+    box-shadow: 0 0 0 3px rgba(blue, 0.25);
+  }
+
+  &:focus:hover,
+  &.selected:focus {
+    box-shadow: 0 0 0 3px rgba(blue, 0.25);
+  }
+
+  &:hover,
+  &.zeroclipboard-is-hover {
+    color: darken($link-color, 2%);
+  }
+
+  &:hover,
+  &:active,
+  &.zeroclipboard-is-hover,
+  &.zeroclipboard-is-active {
+    text-decoration: none;
+    background-color: darken($base-button-color, 1%);
+  }
+
+  &:active,
+  &.selected,
+  &.zeroclipboard-is-active {
+    background-color: darken($base-button-color, 3%);
+    background-image: none;
+    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);
+  }
+
+  &.selected:hover {
+    background-color: darken(#dcdcdc, 5%);
+  }
+
+  &:disabled,
+  &.disabled {
+    &,
+    &:hover {
+      color: rgba(102, 102, 102, 0.5);
+      cursor: default;
+      background-color: rgba(229, 229, 229, 0.5);
+      background-image: none;
+      box-shadow: none;
+    }
+  }
+}
+
+.btn-outline {
+  color: $link-color;
+  background: transparent;
+  box-shadow: inset 0 0 0 2px $grey-lt-300;
+
+  &:hover,
+  &:active,
+  &.zeroclipboard-is-hover,
+  &.zeroclipboard-is-active {
+    color: darken($link-color, 4%);
+    text-decoration: none;
+    background-color: transparent;
+    box-shadow: inset 0 0 0 3px $grey-lt-300;
+  }
+
+  &:focus {
+    text-decoration: none;
+    outline: none;
+    box-shadow:
+      inset 0 0 0 2px $grey-dk-100,
+      0 0 0 3px rgba(blue, 0.25);
+  }
+
+  &:focus:hover,
+  &.selected:focus {
+    box-shadow: inset 0 0 0 2px $grey-dk-100;
+  }
+}
+
+.btn-primary {
+  @include btn-color($white, $btn-primary-color);
+}
+
+.btn-purple {
+  @include btn-color($white, $purple-100);
+}
+
+.btn-blue {
+  @include btn-color($white, $blue-000);
+}
+
+.btn-green {
+  @include btn-color($white, $green-100);
+}
+
+.btn-reset {
+  background: none;
+  border: none;
+  margin: 0;
+  text-align: inherit;
+  font: inherit;
+  border-radius: 0;
+  appearance: none;
+}
diff --git a/docs/_sass/code.scss b/docs/_sass/code.scss
new file mode 100644
index 0000000..d2a5ee1
--- /dev/null
+++ b/docs/_sass/code.scss
@@ -0,0 +1,246 @@
+// Code and syntax highlighting
+// stylelint-disable selector-no-qualifying-type, declaration-block-semicolon-newline-after,declaration-block-single-line-max-declarations, selector-no-type, selector-max-type, scss/comment-no-empty
+
+// {% raw %}
+
+// This instruction applies to all queues not within 'pre' or 'figure', avoiding 'code' generated by the highlight.
+:not(pre, figure) {
+  & > code {
+    padding: 0.2em 0.15em;
+    font-weight: 400;
+    background-color: $code-background-color;
+    border: $border $border-color;
+    border-radius: $border-radius;
+  }
+}
+
+// Avoid appearance of dark border around visited code links in Safari
+a:visited code {
+  border-color: $border-color;
+}
+
+// Content structure for highlighted code blocks using fences or Liquid
+//
+// ```[LANG]...```, no kramdown line_numbers:
+//   div.[language-LANG.]highlighter-rouge > div.highlight > pre.highlight > code
+//
+// ```[LANG]...```, kramdown line_numbers = true:
+//   div.[language-LANG.]highlighter-rouge > div.highlight > pre.highlight > code
+//   > div.table-wrapper > table.rouge-table > tbody > tr
+//   > td.rouge-gutter.gl > pre.lineno
+//   | td.rouge-code > pre
+//
+// {% highlight LANG %}...{% endhighlight %}:
+//   figure.highlight > pre > code.language-LANG
+//
+// {% highlight LANG linenos %}...{% endhighlight %}:
+//   figure.highlight > pre > code.language-LANG
+//   > div.table-wrapper > table.rouge-table > tbody > tr
+//   > td.gutter.gl > pre.lineno
+//   | td.code > pre
+//
+// ----...---- (AsciiDoc)
+//   div.listingblock > div.content > pre.rouge.highlight
+//
+// fix_linenos removes the outermost pre when it encloses table.rouge-table
+//
+// See docs/index-test.md for some tests.
+//
+// No kramdown line_numbers: fences and Liquid highlighting look the same.
+// Kramdown line_numbers = true: fences have a wider gutter than with Liquid?
+
+// ```[LANG]...```
+// or in AsciiDoc:
+//
+//     ----
+//     ...
+//     ----
+
+// the code may appear with 3 different types:
+// container \ case:  default case,          code with line number,   code with html rendering
+// top level:         div.highlighter-rouge, figure.highlight,        figure.highlight
+// second level:      div.highlight,         div.table-wrapper,       pre.highlight
+// third level:       pre.highlight,         td.code,                 absent
+// last level:        code,                  pre,                     code (optionality)
+// highlighter level: span,                  span,                    span
+// the spacing are only in the second level for case 1, 3 and in the third level for case 2
+// in AsciiDoc, there is a parent container that contains optionally a title and the content.
+
+// select top level container
+div.highlighter-rouge,
+div.listingblock > div.content,
+figure.highlight {
+  margin-top: 0;
+  margin-bottom: $sp-3;
+  background-color: $code-background-color;
+  border-radius: $border-radius;
+  box-shadow: none;
+  -webkit-overflow-scrolling: touch;
+  position: relative;
+  padding: 0;
+
+  // copy button (or other button)
+  // the button appear only when there is a hover on the code or focus on button
+  > button {
+    width: $sp-3;
+    opacity: 0;
+    position: absolute;
+    top: 0;
+    right: 0;
+    border: $sp-3 solid $code-background-color;
+    background-color: $code-background-color;
+    color: $body-text-color;
+    box-sizing: content-box;
+
+    svg {
+      fill: $body-text-color;
+    }
+
+    &:active {
+      text-decoration: none;
+      outline: none;
+      opacity: 1;
+    }
+
+    &:focus {
+      opacity: 1;
+    }
+  }
+
+  // the button can be seen by doing a simple hover in the code, there is no need to go over the location of the button
+  &:hover {
+    > button {
+      cursor: copy;
+      opacity: 1;
+    }
+  }
+}
+
+// setting the spacing and scrollbar on the second level for the first case
+// remove all space on the second and third level
+// this is a mixin to accommodate for the slightly different structures generated via Markdown vs AsciiDoc
+@mixin scroll-and-spacing($code-div, $pre-select) {
+  #{$code-div} {
+    overflow-x: auto;
+    padding: $sp-3;
+    margin: 0;
+    border: 0;
+  }
+
+  #{$pre-select},
+  code {
+    padding: 0;
+    margin: 0;
+    border: 0;
+  }
+}
+
+// for Markdown
+div.highlighter-rouge {
+  @include scroll-and-spacing("div.highlight", "pre.highlight");
+}
+
+// for AsciiDoc. we also need to fix the margins for its parent container.
+div.listingblock {
+  @include scroll-and-spacing("div.content", "div.content > pre");
+
+  margin-top: 0;
+  margin-bottom: $sp-3;
+}
+
+// {% highlight LANG %}...{% endhighlight %},
+// {% highlight LANG linenos %}...{% endhighlight %}:
+
+// setting the spacing and scrollbar on the second level for the thirt case
+// the css rule are apply only to the last code enviroment
+// setting the scroolbar
+figure.highlight {
+  pre,
+  :not(pre) > code {
+    overflow-x: auto;
+    padding: $sp-3;
+    margin: 0;
+    border: 0;
+  }
+}
+
+// ```[LANG]...```, kramdown line_numbers = true,
+// {% highlight LANG linenos %}...{% endhighlight %}:
+
+// setting the spacing and scrollbar on the thirt level for the second case
+.highlight .table-wrapper {
+  padding: $sp-3 0;
+  margin: 0;
+  border: 0;
+  box-shadow: none;
+
+  td,
+  pre {
+    @include fs-2;
+
+    min-width: 0;
+    padding: 0;
+    background-color: $code-background-color;
+    border: 0;
+  }
+
+  td.gl {
+    width: 1em;
+    padding-right: $sp-3;
+    padding-left: $sp-3;
+  }
+
+  pre {
+    margin: 0;
+    line-height: 2;
+  }
+}
+
+// Code examples: html render of a code
+.code-example,
+.listingblock > .title {
+  padding: $sp-3;
+  margin-bottom: $sp-3;
+  overflow: auto;
+  border: 1px solid $border-color;
+  border-radius: $border-radius;
+
+  + .highlighter-rouge,
+  + .sectionbody .listingblock,
+  + .content,
+  + figure.highlight {
+    position: relative;
+    margin-top: -$sp-4;
+    border-right: 1px solid $border-color;
+    border-bottom: 1px solid $border-color;
+    border-left: 1px solid $border-color;
+    border-top-left-radius: 0;
+    border-top-right-radius: 0;
+  }
+}
+
+// Mermaid diagram code blocks should be left unstyled.
+code.language-mermaid {
+  padding: 0;
+  background-color: inherit;
+  border: 0;
+}
+
+// Override OneDarkJekyll Colors for Code Blocks
+.highlight,
+pre.highlight {
+  background: $code-background-color; // Code Background
+  // For Backwards Compatibility Before $code-linenumber-color was added
+  @if variable-exists(code-linenumber-color) {
+    color: $code-linenumber-color; // Code Line Numbers
+  } @else {
+    color: $body-text-color; // Code Line Numbers
+  }
+}
+
+// Override OneDarkJekyll Colors for Code Blocks
+.highlight pre {
+  background: $code-background-color; // Code Background
+}
+
+// {% endraw %}
diff --git a/docs/_sass/color_schemes/dark.scss b/docs/_sass/color_schemes/dark.scss
new file mode 100644
index 0000000..6d0999b
--- /dev/null
+++ b/docs/_sass/color_schemes/dark.scss
@@ -0,0 +1,18 @@
+$color-scheme: dark;
+$body-background-color: $grey-dk-300;
+$body-heading-color: $grey-lt-000;
+$body-text-color: $grey-lt-300;
+$link-color: $blue-000;
+$nav-child-link-color: $grey-dk-000;
+$sidebar-color: $grey-dk-300;
+$base-button-color: $grey-dk-250;
+$btn-primary-color: $blue-200;
+$code-background-color: #31343f; // OneDarkJekyll default for syntax-one-dark-vivid
+$code-linenumber-color: #dee2f7; // OneDarkJekyll .nf for syntax-one-dark-vivid
+$feedback-color: darken($sidebar-color, 3%);
+$table-background-color: $grey-dk-250;
+$search-background-color: $grey-dk-250;
+$search-result-preview-color: $grey-dk-000;
+$border-color: $grey-dk-200;
+
+@import "./vendor/OneDarkJekyll/syntax"; // this is the one-dark-vivid atom syntax theme
diff --git a/docs/_sass/color_schemes/legacy_light.scss b/docs/_sass/color_schemes/legacy_light.scss
new file mode 100644
index 0000000..5eaa1ac
--- /dev/null
+++ b/docs/_sass/color_schemes/legacy_light.scss
@@ -0,0 +1,208 @@
+// Moved from _sass/code.scss
+
+.highlight .c {
+  color: #586e75;
+} // comment //
+.highlight .err {
+  color: #93a1a1;
+} // error //
+.highlight .g {
+  color: #93a1a1;
+} // generic //
+.highlight .k {
+  color: #859900;
+} // keyword //
+.highlight .l {
+  color: #93a1a1;
+} // literal //
+.highlight .n {
+  color: #93a1a1;
+} // name //
+.highlight .o {
+  color: #859900;
+} // operator //
+.highlight .x {
+  color: #cb4b16;
+} // other //
+.highlight .p {
+  color: #93a1a1;
+} // punctuation //
+.highlight .cm {
+  color: #586e75;
+} // comment.multiline //
+.highlight .cp {
+  color: #859900;
+} // comment.preproc //
+.highlight .c1 {
+  color: #586e75;
+} // comment.single //
+.highlight .cs {
+  color: #859900;
+} // comment.special //
+.highlight .gd {
+  color: #2aa198;
+} // generic.deleted //
+.highlight .ge {
+  font-style: italic;
+  color: #93a1a1;
+} // generic.emph //
+.highlight .gr {
+  color: #dc322f;
+} // generic.error //
+.highlight .gh {
+  color: #cb4b16;
+} // generic.heading //
+.highlight .gi {
+  color: #859900;
+} // generic.inserted //
+.highlight .go {
+  color: #93a1a1;
+} // generic.output //
+.highlight .gp {
+  color: #93a1a1;
+} // generic.prompt //
+.highlight .gs {
+  font-weight: bold;
+  color: #93a1a1;
+} // generic.strong //
+.highlight .gu {
+  color: #cb4b16;
+} // generic.subheading //
+.highlight .gt {
+  color: #93a1a1;
+} // generic.traceback //
+.highlight .kc {
+  color: #cb4b16;
+} // keyword.constant //
+.highlight .kd {
+  color: #268bd2;
+} // keyword.declaration //
+.highlight .kn {
+  color: #859900;
+} // keyword.namespace //
+.highlight .kp {
+  color: #859900;
+} // keyword.pseudo //
+.highlight .kr {
+  color: #268bd2;
+} // keyword.reserved //
+.highlight .kt {
+  color: #dc322f;
+} // keyword.type //
+.highlight .ld {
+  color: #93a1a1;
+} // literal.date //
+.highlight .m {
+  color: #2aa198;
+} // literal.number //
+.highlight .s {
+  color: #2aa198;
+} // literal.string //
+.highlight .na {
+  color: #555;
+} // name.attribute //
+.highlight .nb {
+  color: #b58900;
+} // name.builtin //
+.highlight .nc {
+  color: #268bd2;
+} // name.class //
+.highlight .no {
+  color: #cb4b16;
+} // name.constant //
+.highlight .nd {
+  color: #268bd2;
+} // name.decorator //
+.highlight .ni {
+  color: #cb4b16;
+} // name.entity //
+.highlight .ne {
+  color: #cb4b16;
+} // name.exception //
+.highlight .nf {
+  color: #268bd2;
+} // name.function //
+.highlight .nl {
+  color: #555;
+} // name.label //
+.highlight .nn {
+  color: #93a1a1;
+} // name.namespace //
+.highlight .nx {
+  color: #555;
+} // name.other //
+.highlight .py {
+  color: #93a1a1;
+} // name.property //
+.highlight .nt {
+  color: #268bd2;
+} // name.tag //
+.highlight .nv {
+  color: #268bd2;
+} // name.variable //
+.highlight .ow {
+  color: #859900;
+} // operator.word //
+.highlight .w {
+  color: #93a1a1;
+} // text.whitespace //
+.highlight .mf {
+  color: #2aa198;
+} // literal.number.float //
+.highlight .mh {
+  color: #2aa198;
+} // literal.number.hex //
+.highlight .mi {
+  color: #2aa198;
+} // literal.number.integer //
+.highlight .mo {
+  color: #2aa198;
+} // literal.number.oct //
+.highlight .sb {
+  color: #586e75;
+} // literal.string.backtick //
+.highlight .sc {
+  color: #2aa198;
+} // literal.string.char //
+.highlight .sd {
+  color: #93a1a1;
+} // literal.string.doc //
+.highlight .s2 {
+  color: #2aa198;
+} // literal.string.double //
+.highlight .se {
+  color: #cb4b16;
+} // literal.string.escape //
+.highlight .sh {
+  color: #93a1a1;
+} // literal.string.heredoc //
+.highlight .si {
+  color: #2aa198;
+} // literal.string.interpol //
+.highlight .sx {
+  color: #2aa198;
+} // literal.string.other //
+.highlight .sr {
+  color: #dc322f;
+} // literal.string.regex //
+.highlight .s1 {
+  color: #2aa198;
+} // literal.string.single //
+.highlight .ss {
+  color: #2aa198;
+} // literal.string.symbol //
+.highlight .bp {
+  color: #268bd2;
+} // name.builtin.pseudo //
+.highlight .vc {
+  color: #268bd2;
+} // name.variable.class //
+.highlight .vg {
+  color: #268bd2;
+} // name.variable.global //
+.highlight .vi {
+  color: #268bd2;
+} // name.variable.instance //
+.highlight .il {
+  color: #2aa198;
+} // literal.number.integer.long //
diff --git a/docs/_sass/color_schemes/light.scss b/docs/_sass/color_schemes/light.scss
new file mode 100644
index 0000000..799e9c6
--- /dev/null
+++ b/docs/_sass/color_schemes/light.scss
@@ -0,0 +1,16 @@
+$color-scheme: light !default;
+$body-background-color: $white !default;
+$body-heading-color: $grey-dk-300 !default;
+$body-text-color: $grey-dk-100 !default;
+$link-color: $purple-000 !default;
+$nav-child-link-color: $grey-dk-100 !default;
+$sidebar-color: $grey-lt-000 !default;
+$base-button-color: #f7f7f7 !default;
+$btn-primary-color: $purple-100 !default;
+$code-background-color: $grey-lt-000 !default;
+$feedback-color: darken($sidebar-color, 3%) !default;
+$table-background-color: $white !default;
+$search-background-color: $white !default;
+$search-result-preview-color: $grey-dk-000 !default;
+
+@import "./vendor/OneLightJekyll/syntax";
diff --git a/docs/_sass/content.scss b/docs/_sass/content.scss
new file mode 100644
index 0000000..219a097
--- /dev/null
+++ b/docs/_sass/content.scss
@@ -0,0 +1,239 @@
+@charset "UTF-8";
+
+// Styles for rendered markdown in the .main-content container
+// stylelint-disable selector-no-type, max-nesting-depth, selector-max-compound-selectors, selector-max-type, selector-max-specificity, selector-max-id
+
+.main-content {
+  line-height: $content-line-height;
+
+  ol,
+  ul,
+  dl,
+  pre,
+  address,
+  blockquote,
+  .table-wrapper {
+    margin-top: 0.5em;
+  }
+
+  a {
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  ul,
+  ol {
+    padding-left: 1.5em;
+  }
+
+  li {
+    .highlight {
+      margin-top: $sp-1;
+    }
+  }
+
+  ol {
+    list-style-type: none;
+    counter-reset: step-counter;
+
+    > li {
+      position: relative;
+
+      &::before {
+        position: absolute;
+        top: 0.2em;
+        left: -1.6em;
+        color: $grey-dk-000;
+        content: counter(step-counter);
+        counter-increment: step-counter;
+        @include fs-3;
+
+        @include mq(sm) {
+          top: 0.11em;
+        }
+      }
+
+      ol {
+        counter-reset: sub-counter;
+
+        > li {
+          &::before {
+            content: counter(sub-counter, lower-alpha);
+            counter-increment: sub-counter;
+          }
+        }
+      }
+    }
+  }
+
+  ul {
+    list-style: none;
+
+    > li {
+      &::before {
+        position: absolute;
+        margin-left: -1.4em;
+        color: $grey-dk-000;
+        content: "•";
+      }
+    }
+  }
+
+  .task-list-item {
+    &::before {
+      content: "";
+    }
+  }
+
+  .task-list-item-checkbox {
+    margin-right: 0.6em;
+    margin-left: -1.4em;
+
+    // The same margin-left is used above for ul > li::before
+  }
+
+  hr + * {
+    margin-top: 0;
+  }
+
+  h1:first-of-type {
+    margin-top: 0.5em;
+  }
+
+  dl {
+    display: grid;
+    grid-template: auto / 10em 1fr;
+  }
+
+  dt,
+  dd {
+    margin: 0.25em 0;
+  }
+
+  dt {
+    grid-column: 1;
+    font-weight: 500;
+    text-align: right;
+
+    &::after {
+      content: ":";
+    }
+  }
+
+  dd {
+    grid-column: 2;
+    margin-bottom: 0;
+    margin-left: 1em;
+
+    blockquote,
+    div,
+    dl,
+    dt,
+    h1,
+    h2,
+    h3,
+    h4,
+    h5,
+    h6,
+    li,
+    ol,
+    p,
+    pre,
+    table,
+    ul,
+    .table-wrapper {
+      &:first-child {
+        margin-top: 0;
+      }
+    }
+  }
+
+  dd,
+  ol,
+  ul {
+    dl:first-child {
+      dt:first-child,
+      dd:nth-child(2) {
+        margin-top: 0;
+      }
+    }
+  }
+
+  .anchor-heading {
+    position: absolute;
+    right: -$sp-4;
+    width: $sp-5;
+    height: 100%;
+    padding-right: $sp-1;
+    padding-left: $sp-1;
+    overflow: visible;
+
+    @include mq(md) {
+      right: auto;
+      left: -$sp-5;
+    }
+
+    svg {
+      display: inline-block;
+      width: 100%;
+      height: 100%;
+      color: $link-color;
+      visibility: hidden;
+    }
+  }
+
+  .anchor-heading:hover,
+  .anchor-heading:focus,
+  h1:hover > .anchor-heading,
+  h2:hover > .anchor-heading,
+  h3:hover > .anchor-heading,
+  h4:hover > .anchor-heading,
+  h5:hover > .anchor-heading,
+  h6:hover > .anchor-heading {
+    svg {
+      visibility: visible;
+    }
+  }
+
+  summary {
+    cursor: pointer;
+  }
+
+  h1,
+  h2,
+  h3,
+  h4,
+  h5,
+  h6,
+  #toctitle {
+    position: relative;
+    margin-top: 1.5em;
+    margin-bottom: 0.25em;
+
+    + table,
+    + .table-wrapper,
+    + .code-example,
+    + .highlighter-rouge,
+    + .sectionbody .listingblock {
+      margin-top: 1em;
+    }
+
+    + p:not(.label) {
+      margin-top: 0;
+    }
+  }
+
+  > h1:first-child,
+  > h2:first-child,
+  > h3:first-child,
+  > h4:first-child,
+  > h5:first-child,
+  > h6:first-child,
+  > .sect1:first-child > h2,
+  > .sect2:first-child > h3,
+  > .sect3:first-child > h4,
+  > .sect4:first-child > h5,
+  > .sect5:first-child > h6 {
+    margin-top: $sp-2;
+  }
+}
diff --git a/docs/_sass/custom/custom.scss b/docs/_sass/custom/custom.scss
new file mode 100644
index 0000000..ac8445a
--- /dev/null
+++ b/docs/_sass/custom/custom.scss
@@ -0,0 +1,1 @@
+// custom SCSS (or CSS) goes here
diff --git a/docs/_sass/custom/setup.scss b/docs/_sass/custom/setup.scss
new file mode 100644
index 0000000..c3b0a94
--- /dev/null
+++ b/docs/_sass/custom/setup.scss
@@ -0,0 +1,1 @@
+// custom setup code goes here
diff --git a/docs/_sass/labels.scss b/docs/_sass/labels.scss
new file mode 100644
index 0000000..98cc8f9
--- /dev/null
+++ b/docs/_sass/labels.scss
@@ -0,0 +1,37 @@
+// Labels (not the form kind)
+
+// this :not() prevents a style clash with Mermaid.js's
+// diagram labels, which also use .label
+// for more, see https://github.com/just-the-docs/just-the-docs/issues/1272
+// and the accompanying PR
+.label:not(g),
+.label-blue:not(g) {
+  display: inline-block;
+  padding: 0.16em 0.56em;
+  margin-right: $sp-2;
+  margin-left: $sp-2;
+  color: $white;
+  text-transform: uppercase;
+  vertical-align: middle;
+  background-color: $blue-100;
+  @include fs-2;
+
+  border-radius: 12px;
+}
+
+.label-green:not(g) {
+  background-color: $green-200;
+}
+
+.label-purple:not(g) {
+  background-color: $purple-100;
+}
+
+.label-red:not(g) {
+  background-color: $red-200;
+}
+
+.label-yellow:not(g) {
+  color: $grey-dk-200;
+  background-color: $yellow-200;
+}
diff --git a/docs/_sass/layout.scss b/docs/_sass/layout.scss
new file mode 100644
index 0000000..027b388
--- /dev/null
+++ b/docs/_sass/layout.scss
@@ -0,0 +1,209 @@
+// The basic two column layout
+
+.side-bar {
+  z-index: 0;
+  display: flex;
+  flex-wrap: wrap;
+  background-color: $sidebar-color;
+
+  @include mq(md) {
+    flex-flow: column nowrap;
+    position: fixed;
+    width: $nav-width-md;
+    height: 100%;
+    border-right: $border $border-color;
+    align-items: flex-end;
+  }
+
+  @include mq(lg) {
+    width: calc((100% - #{$nav-width + $content-width}) / 2 + #{$nav-width});
+    min-width: $nav-width;
+  }
+}
+
+.main {
+  @include mq(md) {
+    position: relative;
+    max-width: $content-width;
+    margin-left: $nav-width-md;
+  }
+
+  @include mq(lg) {
+    // stylelint-disable function-name-case
+    // disable for Max(), we want to use the CSS max() function
+    margin-left: Max(
+      #{$nav-width},
+      calc((100% - #{$nav-width + $content-width}) / 2 + #{$nav-width})
+    );
+    // stylelint-enable function-name-case
+  }
+}
+
+.main-content-wrap {
+  @include container;
+
+  padding-top: $gutter-spacing-sm;
+  padding-bottom: $gutter-spacing-sm;
+
+  @include mq(md) {
+    padding-top: $gutter-spacing;
+    padding-bottom: $gutter-spacing;
+  }
+}
+
+.main-header {
+  z-index: 0;
+  display: none;
+  background-color: $sidebar-color;
+
+  @include mq(md) {
+    display: flex;
+    justify-content: space-between;
+    height: $header-height;
+    background-color: $body-background-color;
+    border-bottom: $border $border-color;
+  }
+
+  &.nav-open {
+    display: block;
+
+    @include mq(md) {
+      display: flex;
+    }
+  }
+}
+
+.site-nav,
+.site-header,
+.site-footer {
+  width: 100%;
+
+  @include mq(lg) {
+    width: $nav-width;
+  }
+}
+
+.site-nav {
+  display: none;
+
+  &.nav-open {
+    display: block;
+  }
+
+  @include mq(md) {
+    display: block;
+    padding-top: $sp-8;
+    padding-bottom: $gutter-spacing-sm;
+    overflow-y: auto;
+    flex: 1 1 auto;
+  }
+}
+
+.site-header {
+  display: flex;
+  min-height: $header-height;
+  align-items: center;
+
+  @include mq(md) {
+    height: $header-height;
+    max-height: $header-height;
+    border-bottom: $border $border-color;
+  }
+}
+
+.site-title {
+  @include container;
+
+  flex-grow: 1;
+  display: flex;
+  height: 100%;
+  align-items: center;
+  padding-top: $sp-3;
+  padding-bottom: $sp-3;
+  color: $body-heading-color;
+  @include fs-6;
+
+  @include mq(md) {
+    padding-top: $sp-2;
+    padding-bottom: $sp-2;
+  }
+}
+
+@if variable-exists(logo) {
+  .site-logo {
+    width: 100%;
+    height: 100%;
+    background-image: url($logo);
+    background-repeat: no-repeat;
+    background-position: left center;
+    background-size: contain;
+  }
+}
+
+.site-button {
+  display: flex;
+  height: 100%;
+  padding: $gutter-spacing-sm;
+  align-items: center;
+}
+
+@include mq(md) {
+  .site-header .site-button {
+    display: none;
+  }
+}
+
+.site-title:hover {
+  background-image: linear-gradient(
+    -90deg,
+    rgba($feedback-color, 1) 0%,
+    rgba($feedback-color, 0.8) 80%,
+    rgba($feedback-color, 0) 100%
+  );
+}
+
+.site-button:hover {
+  background-image: linear-gradient(
+    -90deg,
+    rgba($feedback-color, 1) 0%,
+    rgba($feedback-color, 0.8) 100%
+  );
+}
+
+// stylelint-disable selector-max-type
+
+body {
+  position: relative;
+  padding-bottom: $sp-10;
+  overflow-y: scroll;
+
+  @include mq(md) {
+    position: static;
+    padding-bottom: 0;
+  }
+}
+
+// stylelint-enable selector-max-type
+
+.site-footer {
+  @include container;
+
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  padding-top: $sp-4;
+  padding-bottom: $sp-4;
+  color: $grey-dk-000;
+  @include fs-2;
+
+  @include mq(md) {
+    position: static;
+    justify-self: end;
+  }
+}
+
+.icon {
+  width: $sp-5;
+  height: $sp-5;
+  color: $link-color;
+}
diff --git a/docs/_sass/modules.scss b/docs/_sass/modules.scss
new file mode 100644
index 0000000..ee282e7
--- /dev/null
+++ b/docs/_sass/modules.scss
@@ -0,0 +1,17 @@
+// Import external dependencies
+@import "./vendor/normalize.scss/normalize";
+
+// Modules
+@import "./base";
+@import "./layout";
+@import "./content";
+@import "./navigation";
+@import "./typography";
+@import "./labels";
+@import "./buttons";
+@import "./search";
+@import "./tables";
+@import "./code";
+@import "./utilities/utilities";
+@import "./print";
+@import "./skiptomain";
diff --git a/docs/_sass/navigation.scss b/docs/_sass/navigation.scss
new file mode 100644
index 0000000..011a32e
--- /dev/null
+++ b/docs/_sass/navigation.scss
@@ -0,0 +1,235 @@
+// Main nav, breadcrumb, etc...
+// stylelint-disable selector-no-type, max-nesting-depth, selector-max-compound-selectors, selector-max-type, selector-max-specificity
+
+.nav-list {
+  padding: 0;
+  margin-top: 0;
+  margin-bottom: 0;
+  list-style: none;
+
+  .nav-list-item {
+    @include fs-4;
+
+    position: relative;
+    margin: 0;
+
+    @include mq(md) {
+      @include fs-3;
+    }
+
+    .nav-list-link {
+      display: block;
+      min-height: $nav-list-item-height-sm;
+      padding-top: $sp-1;
+      padding-bottom: $sp-1;
+      line-height: #{$nav-list-item-height-sm - 2 * $sp-1};
+      @if $nav-list-expander-right {
+        padding-right: $nav-list-item-height-sm;
+        padding-left: $gutter-spacing-sm;
+      } @else {
+        padding-right: $gutter-spacing-sm;
+        padding-left: $nav-list-item-height-sm;
+      }
+
+      @include mq(md) {
+        min-height: $nav-list-item-height;
+        line-height: #{$nav-list-item-height - 2 * $sp-1};
+        @if $nav-list-expander-right {
+          padding-right: $nav-list-item-height;
+          padding-left: $gutter-spacing;
+        } @else {
+          padding-right: $gutter-spacing;
+          padding-left: $nav-list-item-height;
+        }
+      }
+
+      &.external > svg {
+        width: $sp-4;
+        height: $sp-4;
+        vertical-align: text-bottom;
+      }
+
+      &.active {
+        font-weight: 600;
+        text-decoration: none;
+      }
+
+      &:hover,
+      &.active {
+        background-image: linear-gradient(
+          -90deg,
+          rgba($feedback-color, 1) 0%,
+          rgba($feedback-color, 0.8) 80%,
+          rgba($feedback-color, 0) 100%
+        );
+      }
+    }
+
+    .nav-list-expander {
+      position: absolute;
+      @if $nav-list-expander-right {
+        right: 0;
+      }
+
+      width: $nav-list-item-height-sm;
+      height: $nav-list-item-height-sm;
+      padding: #{$nav-list-item-height-sm * 0.25};
+      color: $link-color;
+
+      @include mq(md) {
+        width: $nav-list-item-height;
+        height: $nav-list-item-height;
+        padding: #{$nav-list-item-height * 0.25};
+      }
+
+      &:hover {
+        background-image: linear-gradient(
+          -90deg,
+          rgba($feedback-color, 1) 0%,
+          rgba($feedback-color, 0.8) 100%
+        );
+      }
+
+      @if $nav-list-expander-right {
+        svg {
+          transform: rotate(90deg);
+        }
+      }
+    }
+
+    > .nav-list {
+      display: none;
+      padding-left: $sp-3;
+      list-style: none;
+
+      .nav-list-item {
+        position: relative;
+
+        .nav-list-link {
+          color: $nav-child-link-color;
+        }
+
+        .nav-list-expander {
+          color: $nav-child-link-color;
+        }
+      }
+    }
+
+    &.active {
+      > .nav-list-expander svg {
+        @if $nav-list-expander-right {
+          transform: rotate(-90deg);
+        } @else {
+          transform: rotate(90deg);
+        }
+      }
+
+      > .nav-list {
+        display: block;
+      }
+    }
+  }
+}
+
+.nav-category {
+  padding: $sp-2 $gutter-spacing-sm;
+  font-weight: 600;
+  text-align: start;
+  text-transform: uppercase;
+  border-bottom: $border $border-color;
+  @include fs-2;
+
+  @include mq(md) {
+    padding: $sp-2 $gutter-spacing;
+    margin-top: $gutter-spacing-sm;
+    text-align: start;
+
+    &:first-child {
+      margin-top: 0;
+    }
+  }
+}
+
+.nav-list.nav-category-list {
+  > .nav-list-item {
+    margin: 0;
+
+    > .nav-list {
+      padding: 0;
+
+      > .nav-list-item {
+        > .nav-list-link {
+          color: $link-color;
+        }
+
+        > .nav-list-expander {
+          color: $link-color;
+        }
+      }
+    }
+  }
+}
+
+// Aux nav
+
+.aux-nav {
+  height: 100%;
+  overflow-x: auto;
+  @include fs-2;
+
+  .aux-nav-list {
+    display: flex;
+    height: 100%;
+    padding: 0;
+    margin: 0;
+    list-style: none;
+  }
+
+  .aux-nav-list-item {
+    display: inline-block;
+    height: 100%;
+    padding: 0;
+    margin: 0;
+  }
+
+  @include mq(md) {
+    padding-right: $gutter-spacing-sm;
+  }
+}
+
+// Breadcrumb nav
+
+.breadcrumb-nav {
+  @include mq(md) {
+    margin-top: -$sp-4;
+  }
+}
+
+.breadcrumb-nav-list {
+  padding-left: 0;
+  margin-bottom: $sp-3;
+  list-style: none;
+}
+
+.breadcrumb-nav-list-item {
+  display: table-cell;
+  @include fs-2;
+
+  &::before {
+    display: none;
+  }
+
+  &::after {
+    display: inline-block;
+    margin-right: $sp-2;
+    margin-left: $sp-2;
+    color: $grey-dk-000;
+    content: "/";
+  }
+
+  &:last-child {
+    &::after {
+      content: "";
+    }
+  }
+}
diff --git a/docs/_sass/print.scss b/docs/_sass/print.scss
new file mode 100644
index 0000000..ee76a3c
--- /dev/null
+++ b/docs/_sass/print.scss
@@ -0,0 +1,40 @@
+// stylelint-disable selector-max-specificity, selector-max-id, selector-max-type, selector-no-qualifying-type
+
+@media print {
+  .site-footer,
+  .site-button,
+  #edit-this-page,
+  #back-to-top,
+  .site-nav,
+  .main-header {
+    display: none !important;
+  }
+
+  .side-bar {
+    width: 100%;
+    height: auto;
+    border-right: 0 !important;
+  }
+
+  .site-header {
+    border-bottom: 1px solid $border-color;
+  }
+
+  .site-title {
+    font-size: 1rem !important;
+    font-weight: 700 !important;
+  }
+
+  .text-small {
+    font-size: 8pt !important;
+  }
+
+  pre.highlight {
+    border: 1px solid $border-color;
+  }
+
+  .main {
+    max-width: none;
+    margin-left: 0;
+  }
+}
diff --git a/docs/_sass/search.scss b/docs/_sass/search.scss
new file mode 100644
index 0000000..cdf8d6e
--- /dev/null
+++ b/docs/_sass/search.scss
@@ -0,0 +1,324 @@
+// Search input and autocomplete
+
+.search {
+  position: relative;
+  z-index: 2;
+  flex-grow: 1;
+  height: $sp-10;
+  padding: $sp-2;
+  transition: padding linear #{$transition-duration * 0.5};
+
+  @include mq(md) {
+    position: relative !important;
+    width: auto !important;
+    height: 100% !important;
+    padding: 0;
+    transition: none;
+  }
+}
+
+.search-input-wrap {
+  position: relative;
+  z-index: 1;
+  height: $sp-8;
+  overflow: hidden;
+  border-radius: $border-radius;
+  box-shadow:
+    0 1px 2px rgba(0, 0, 0, 0.12),
+    0 3px 10px rgba(0, 0, 0, 0.08);
+  transition: height linear #{$transition-duration * 0.5};
+
+  @include mq(md) {
+    position: absolute;
+    width: 100%;
+    max-width: $search-results-width;
+    height: 100% !important;
+    border-radius: 0;
+    box-shadow: none;
+    transition: width ease $transition-duration;
+  }
+}
+
+.search-input {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  padding: $sp-2 $gutter-spacing-sm $sp-2 #{$gutter-spacing-sm + $sp-5};
+  font-size: 1rem;
+  color: $body-text-color;
+  background-color: $search-background-color;
+  border-top: 0;
+  border-right: 0;
+  border-bottom: 0;
+  border-left: 0;
+  border-radius: 0;
+
+  @include mq(md) {
+    padding: $sp-2 $gutter-spacing-sm $sp-2 #{$gutter-spacing + $sp-5};
+    font-size: 0.875rem;
+    background-color: $body-background-color;
+    transition: padding-left linear #{$transition-duration * 0.5};
+  }
+
+  &:focus {
+    outline: 0;
+
+    + .search-label .search-icon {
+      color: $link-color;
+    }
+  }
+}
+
+.search-label {
+  position: absolute;
+  display: flex;
+  height: 100%;
+  padding-left: $gutter-spacing-sm;
+
+  @include mq(md) {
+    padding-left: $gutter-spacing;
+    transition: padding-left linear #{$transition-duration * 0.5};
+  }
+
+  .search-icon {
+    width: #{$sp-4 * 1.2};
+    height: #{$sp-4 * 1.2};
+    align-self: center;
+    color: $grey-dk-000;
+  }
+}
+
+.search-results {
+  position: absolute;
+  left: 0;
+  display: none;
+  width: 100%;
+  max-height: calc(100% - #{$sp-10});
+  overflow-y: auto;
+  background-color: $search-background-color;
+  border-bottom-right-radius: $border-radius;
+  border-bottom-left-radius: $border-radius;
+  box-shadow:
+    0 1px 2px rgba(0, 0, 0, 0.12),
+    0 3px 10px rgba(0, 0, 0, 0.08);
+
+  @include mq(md) {
+    top: 100%;
+    width: $search-results-width;
+    max-height: calc(100vh - 200%) !important;
+  }
+}
+
+.search-results-list {
+  padding-left: 0;
+  margin-bottom: $sp-1;
+  list-style: none;
+  @include fs-4;
+
+  @include mq(md) {
+    @include fs-3;
+  }
+}
+
+.search-results-list-item {
+  padding: 0;
+  margin: 0;
+}
+
+.search-result {
+  display: block;
+  padding: $sp-1 $sp-3;
+
+  &:hover,
+  &.active {
+    background-color: $feedback-color;
+  }
+}
+
+.search-result-title {
+  display: block;
+  padding-top: $sp-2;
+  padding-bottom: $sp-2;
+
+  @include mq(sm) {
+    display: inline-block;
+    width: 40%;
+    padding-right: $sp-2;
+    vertical-align: top;
+  }
+}
+
+.search-result-doc {
+  display: flex;
+  align-items: center;
+  word-wrap: break-word;
+
+  &.search-result-doc-parent {
+    opacity: 0.5;
+    @include fs-3;
+
+    @include mq(md) {
+      @include fs-2;
+    }
+  }
+
+  .search-result-icon {
+    width: $sp-4;
+    height: $sp-4;
+    margin-right: $sp-2;
+    color: $link-color;
+    flex-shrink: 0;
+  }
+
+  .search-result-doc-title {
+    overflow: auto;
+  }
+}
+
+.search-result-section {
+  margin-left: #{$sp-4 + $sp-2};
+  word-wrap: break-word;
+}
+
+.search-result-rel-url {
+  display: block;
+  margin-left: #{$sp-4 + $sp-2};
+  overflow: hidden;
+  color: $search-result-preview-color;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  @include fs-1;
+}
+
+.search-result-previews {
+  display: block;
+  padding-top: $sp-2;
+  padding-bottom: $sp-2;
+  padding-left: $sp-4;
+  margin-left: $sp-2;
+  color: $search-result-preview-color;
+  word-wrap: break-word;
+  border-left: $border;
+  border-left-color: $border-color;
+  @include fs-2;
+
+  @include mq(sm) {
+    display: inline-block;
+    width: 60%;
+    padding-left: $sp-2;
+    margin-left: 0;
+    vertical-align: top;
+  }
+}
+
+.search-result-preview + .search-result-preview {
+  margin-top: $sp-1;
+}
+
+.search-result-highlight {
+  font-weight: bold;
+}
+
+.search-no-result {
+  padding: $sp-2 $sp-3;
+  @include fs-3;
+}
+
+.search-button {
+  position: fixed;
+  right: $sp-4;
+  bottom: $sp-4;
+  display: flex;
+  width: $sp-9;
+  height: $sp-9;
+  background-color: $search-background-color;
+  border: 1px solid rgba($link-color, 0.3);
+  border-radius: #{$sp-9 * 0.5};
+  box-shadow:
+    0 1px 2px rgba(0, 0, 0, 0.12),
+    0 3px 10px rgba(0, 0, 0, 0.08);
+  align-items: center;
+  justify-content: center;
+}
+
+.search-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 1;
+  width: 0;
+  height: 0;
+  background-color: rgba(0, 0, 0, 0.3);
+  opacity: 0;
+  transition:
+    opacity ease $transition-duration,
+    width 0s $transition-duration,
+    height 0s $transition-duration;
+}
+
+.search-active {
+  .search {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    padding: 0;
+  }
+
+  .search-input-wrap {
+    height: $sp-10;
+    border-radius: 0;
+
+    @include mq(md) {
+      width: $search-results-width;
+      box-shadow:
+        0 1px 2px rgba(0, 0, 0, 0.12),
+        0 3px 10px rgba(0, 0, 0, 0.08);
+    }
+  }
+
+  .search-input {
+    background-color: $search-background-color;
+
+    @include mq(md) {
+      padding-left: 2.3rem;
+    }
+  }
+
+  .search-label {
+    @include mq(md) {
+      padding-left: 0.6rem;
+    }
+  }
+
+  .search-results {
+    display: block;
+  }
+
+  .search-overlay {
+    width: 100%;
+    height: 100%;
+    opacity: 1;
+    transition:
+      opacity ease $transition-duration,
+      width 0s,
+      height 0s;
+  }
+
+  @include mq(md) {
+    .main {
+      position: fixed;
+      right: 0;
+      left: 0;
+    }
+  }
+
+  .main-header {
+    padding-top: $sp-10;
+
+    @include mq(md) {
+      padding-top: 0;
+    }
+  }
+}
diff --git a/docs/_sass/skiptomain.scss b/docs/_sass/skiptomain.scss
new file mode 100644
index 0000000..7c14f05
--- /dev/null
+++ b/docs/_sass/skiptomain.scss
@@ -0,0 +1,30 @@
+// Skipnav
+// Skip to main content
+
+a.skip-to-main {
+  left: -999px;
+  position: absolute;
+  top: auto;
+  width: 1px;
+  height: 1px;
+  overflow: hidden;
+  z-index: -999;
+}
+
+a.skip-to-main:focus,
+a.skip-to-main:active {
+  color: $link-color;
+  background-color: $body-background-color;
+  left: auto;
+  top: auto;
+  width: 30%;
+  height: auto;
+  overflow: auto;
+  margin: 10px 35%;
+  padding: 5px;
+  border-radius: 15px;
+  border: 4px solid $btn-primary-color;
+  text-align: center;
+  font-size: 1.2em;
+  z-index: 999;
+}
diff --git a/docs/_sass/support/_variables.scss b/docs/_sass/support/_variables.scss
new file mode 100644
index 0000000..0b051ff
--- /dev/null
+++ b/docs/_sass/support/_variables.scss
@@ -0,0 +1,117 @@
+// Typography
+
+// prettier-ignore
+$body-font-family: system-ui, -apple-system, blinkmacsystemfont, "Segoe UI",
+  roboto, "Helvetica Neue", arial, sans-serif, "Segoe UI Emoji" !default;
+$mono-font-family: "SFMono-Regular", menlo, consolas, monospace !default;
+$root-font-size: 16px !default; // DEPRECATED: previously base font-size for rems
+$body-line-height: 1.4 !default;
+$content-line-height: 1.6 !default;
+$body-heading-line-height: 1.25 !default;
+
+// Font size
+// `-sm` suffix is the size at the small (and above) media query
+
+$font-size-1: 0.5625rem !default;
+$font-size-1-sm: 0.625rem !default;
+$font-size-2: 0.6875rem !default; // h4 - uppercased!, h6 not uppercased, text-small
+$font-size-3: 0.75rem !default; // h5
+$font-size-4: 0.875rem !default;
+$font-size-5: 1rem !default; // h3
+$font-size-6: 1.125rem !default; // h2
+$font-size-7: 1.5rem !default;
+$font-size-8: 2rem !default; // h1
+$font-size-9: 2.25rem !default;
+$font-size-10: 2.625rem !default;
+$font-size-10-sm: 3rem !default;
+
+// Colors
+
+$white: #fff !default;
+$grey-dk-000: #959396 !default;
+$grey-dk-100: #5c5962 !default;
+$grey-dk-200: #44434d !default;
+$grey-dk-250: #302d36 !default;
+$grey-dk-300: #27262b !default;
+$grey-lt-000: #f5f6fa !default;
+$grey-lt-100: #eeebee !default;
+$grey-lt-200: #ecebed !default;
+$grey-lt-300: #e6e1e8 !default;
+$purple-000: #7253ed !default;
+$purple-100: #5e41d0 !default;
+$purple-200: #4e26af !default;
+$purple-300: #381885 !default;
+$blue-000: #2c84fa !default;
+$blue-100: #2869e6 !default;
+$blue-200: #264caf !default;
+$blue-300: #183385 !default;
+$green-000: #41d693 !default;
+$green-100: #11b584 !default;
+$green-200: #009c7b !default;
+$green-300: #026e57 !default;
+$yellow-000: #ffeb82 !default;
+$yellow-100: #fadf50 !default;
+$yellow-200: #f7d12e !default;
+$yellow-300: #e7af06 !default;
+$red-000: #f77e7e !default;
+$red-100: #f96e65 !default;
+$red-200: #e94c4c !default;
+$red-300: #dd2e2e !default;
+
+// Spacing
+
+$spacing-unit: 1rem; // 1rem == 16px
+
+$spacers: (
+  sp-0: 0,
+  sp-1: $spacing-unit * 0.25,
+  sp-2: $spacing-unit * 0.5,
+  sp-3: $spacing-unit * 0.75,
+  sp-4: $spacing-unit,
+  sp-5: $spacing-unit * 1.5,
+  sp-6: $spacing-unit * 2,
+  sp-7: $spacing-unit * 2.5,
+  sp-8: $spacing-unit * 3,
+  sp-9: $spacing-unit * 3.5,
+  sp-10: $spacing-unit * 4,
+) !default;
+$sp-1: map-get($spacers, sp-1) !default; // 0.25 rem == 4px
+$sp-2: map-get($spacers, sp-2) !default; // 0.5  rem == 8px
+$sp-3: map-get($spacers, sp-3) !default; // 0.75 rem == 12px
+$sp-4: map-get($spacers, sp-4) !default; // 1    rem == 16px
+$sp-5: map-get($spacers, sp-5) !default; // 1.5  rem == 24px
+$sp-6: map-get($spacers, sp-6) !default; // 2    rem == 32px
+$sp-7: map-get($spacers, sp-7) !default; // 2.5  rem == 40px
+$sp-8: map-get($spacers, sp-8) !default; // 3    rem == 48px
+$sp-9: map-get($spacers, sp-9) !default; // 3.5  rem == 56px
+$sp-10: map-get($spacers, sp-10) !default; // 4  rem == 64px
+
+// Borders
+
+$border: 1px solid !default;
+$border-radius: 4px !default;
+$border-color: $grey-lt-100 !default;
+
+// Grid system
+
+$gutter-spacing: $sp-6 !default;
+$gutter-spacing-sm: $sp-4 !default;
+$nav-width: 16.5rem !default;
+$nav-width-md: 15.5rem !default;
+$nav-list-item-height: $sp-6 !default;
+$nav-list-item-height-sm: $sp-8 !default;
+$nav-list-expander-right: true;
+$content-width: 50rem !default;
+$header-height: 3.75rem !default;
+$search-results-width: $content-width - $nav-width !default;
+$transition-duration: 400ms;
+
+// Media queries in pixels
+
+$media-queries: (
+  xs: 20rem,
+  sm: 31.25rem,
+  md: $content-width,
+  lg: $content-width + $nav-width,
+  xl: 87.5rem,
+) !default;
diff --git a/docs/_sass/support/mixins/_buttons.scss b/docs/_sass/support/mixins/_buttons.scss
new file mode 100644
index 0000000..cd51da3
--- /dev/null
+++ b/docs/_sass/support/mixins/_buttons.scss
@@ -0,0 +1,29 @@
+// Colored button
+
+@mixin btn-color($fg, $bg) {
+  color: $fg;
+  background-color: darken($bg, 2%);
+  background-image: linear-gradient(lighten($bg, 5%), darken($bg, 2%));
+  box-shadow:
+    0 1px 3px rgba(0, 0, 0, 0.25),
+    0 4px 10px rgba(0, 0, 0, 0.12);
+
+  &:hover,
+  &.zeroclipboard-is-hover {
+    color: $fg;
+    background-color: darken($bg, 4%);
+    background-image: linear-gradient((lighten($bg, 2%), darken($bg, 4%)));
+  }
+
+  &:active,
+  &.selected,
+  &.zeroclipboard-is-active {
+    background-color: darken($bg, 5%);
+    background-image: none;
+    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);
+  }
+
+  &.selected:hover {
+    background-color: darken($bg, 10%);
+  }
+}
diff --git a/docs/_sass/support/mixins/_layout.scss b/docs/_sass/support/mixins/_layout.scss
new file mode 100644
index 0000000..a9b32ee
--- /dev/null
+++ b/docs/_sass/support/mixins/_layout.scss
@@ -0,0 +1,33 @@
+// Media query
+
+// Media query mixin
+// Usage:
+// @include mq(md) {
+//   ..medium and up styles
+// }
+@mixin mq($name) {
+  // Retrieves the value from the key
+  $value: map-get($media-queries, $name);
+
+  // If the key exists in the map
+  @if $value {
+    // Prints a media query based on the value
+    @media (min-width: $value) {
+      @content;
+    }
+  } @else {
+    @warn "No value could be retrieved from `#{$media-query}`. Please make sure it is defined in `$media-queries` map.";
+  }
+}
+
+// Responsive container
+
+@mixin container {
+  padding-right: $gutter-spacing-sm;
+  padding-left: $gutter-spacing-sm;
+
+  @include mq(md) {
+    padding-right: $gutter-spacing;
+    padding-left: $gutter-spacing;
+  }
+}
diff --git a/docs/_sass/support/mixins/_typography.scss b/docs/_sass/support/mixins/_typography.scss
new file mode 100644
index 0000000..5207fcd
--- /dev/null
+++ b/docs/_sass/support/mixins/_typography.scss
@@ -0,0 +1,84 @@
+@mixin fs-1 {
+  font-size: $font-size-1 !important;
+
+  @include mq(sm) {
+    font-size: $font-size-1-sm !important;
+  }
+}
+
+@mixin fs-2 {
+  font-size: $font-size-2 !important;
+
+  @include mq(sm) {
+    font-size: $font-size-3 !important;
+  }
+}
+
+@mixin fs-3 {
+  font-size: $font-size-3 !important;
+
+  @include mq(sm) {
+    font-size: $font-size-4 !important;
+  }
+}
+
+@mixin fs-4 {
+  font-size: $font-size-4 !important;
+
+  @include mq(sm) {
+    font-size: $font-size-5 !important;
+  }
+}
+
+@mixin fs-5 {
+  font-size: $font-size-5 !important;
+
+  @include mq(sm) {
+    font-size: $font-size-6 !important;
+  }
+}
+
+@mixin fs-6 {
+  font-size: $font-size-6 !important;
+
+  @include mq(sm) {
+    font-size: $font-size-7 !important;
+    line-height: $body-heading-line-height;
+  }
+}
+
+@mixin fs-7 {
+  font-size: $font-size-7 !important;
+  line-height: $body-heading-line-height;
+
+  @include mq(sm) {
+    font-size: $font-size-8 !important;
+  }
+}
+
+@mixin fs-8 {
+  font-size: $font-size-8 !important;
+  line-height: $body-heading-line-height;
+
+  @include mq(sm) {
+    font-size: $font-size-9 !important;
+  }
+}
+
+@mixin fs-9 {
+  font-size: $font-size-9 !important;
+  line-height: $body-heading-line-height;
+
+  @include mq(sm) {
+    font-size: $font-size-10 !important;
+  }
+}
+
+@mixin fs-10 {
+  font-size: $font-size-10 !important;
+  line-height: $body-heading-line-height;
+
+  @include mq(sm) {
+    font-size: $font-size-10-sm !important;
+  }
+}
diff --git a/docs/_sass/support/mixins/mixins.scss b/docs/_sass/support/mixins/mixins.scss
new file mode 100644
index 0000000..0506fbf
--- /dev/null
+++ b/docs/_sass/support/mixins/mixins.scss
@@ -0,0 +1,3 @@
+@import "./layout";
+@import "./buttons";
+@import "./typography";
diff --git a/docs/_sass/support/support.scss b/docs/_sass/support/support.scss
new file mode 100644
index 0000000..e800592
--- /dev/null
+++ b/docs/_sass/support/support.scss
@@ -0,0 +1,2 @@
+@import "./variables";
+@import "./mixins/mixins";
diff --git a/docs/_sass/tables.scss b/docs/_sass/tables.scss
new file mode 100644
index 0000000..c5d8491
--- /dev/null
+++ b/docs/_sass/tables.scss
@@ -0,0 +1,56 @@
+// Tables
+// stylelint-disable max-nesting-depth, selector-no-type, selector-max-type
+
+.table-wrapper {
+  display: block;
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: $sp-5;
+  overflow-x: auto;
+  border-radius: $border-radius;
+  box-shadow:
+    0 1px 2px rgba(0, 0, 0, 0.12),
+    0 3px 10px rgba(0, 0, 0, 0.08);
+}
+
+table {
+  display: table;
+  min-width: 100%;
+  border-collapse: separate;
+}
+
+th,
+td {
+  @include fs-3;
+
+  min-width: 7.5rem;
+  padding: $sp-2 $sp-3;
+  background-color: $table-background-color;
+  border-bottom: $border rgba($border-color, 0.5);
+  border-left: $border $border-color;
+
+  &:first-of-type {
+    border-left: 0;
+  }
+}
+
+tbody {
+  tr {
+    &:last-of-type {
+      th,
+      td {
+        border-bottom: 0;
+      }
+
+      td {
+        padding-bottom: $sp-3;
+      }
+    }
+  }
+}
+
+thead {
+  th {
+    border-bottom: $border $border-color;
+  }
+}
diff --git a/docs/_sass/typography.scss b/docs/_sass/typography.scss
new file mode 100644
index 0000000..441dcae
--- /dev/null
+++ b/docs/_sass/typography.scss
@@ -0,0 +1,63 @@
+// Typography
+// stylelint-disable selector-no-type, selector-max-type, selector-max-specificity, selector-max-id
+
+h1,
+.text-alpha {
+  @include fs-8;
+
+  font-weight: 300;
+}
+
+h2,
+.text-beta,
+#toctitle {
+  @include fs-6;
+}
+
+h3,
+.text-gamma {
+  @include fs-5;
+}
+
+h4,
+.text-delta {
+  @include fs-2;
+
+  font-weight: 400;
+  text-transform: uppercase;
+  letter-spacing: 0.1em;
+}
+
+h4 code {
+  text-transform: none;
+}
+
+h5,
+.text-epsilon {
+  @include fs-3;
+}
+
+h6,
+.text-zeta {
+  @include fs-2;
+}
+
+.text-small {
+  @include fs-2;
+}
+
+.text-mono {
+  font-family: $mono-font-family !important;
+}
+
+.text-left {
+  text-align: left !important;
+}
+
+.text-center {
+  text-align: center !important;
+}
+
+.text-right {
+  text-align: right !important;
+}
diff --git a/docs/_sass/utilities/_colors.scss b/docs/_sass/utilities/_colors.scss
new file mode 100644
index 0000000..9025649
--- /dev/null
+++ b/docs/_sass/utilities/_colors.scss
@@ -0,0 +1,237 @@
+// Utility classes for colors
+
+// Text colors
+
+.text-grey-dk-000 {
+  color: $grey-dk-000 !important;
+}
+
+.text-grey-dk-100 {
+  color: $grey-dk-100 !important;
+}
+
+.text-grey-dk-200 {
+  color: $grey-dk-200 !important;
+}
+
+.text-grey-dk-250 {
+  color: $grey-dk-250 !important;
+}
+
+.text-grey-dk-300 {
+  color: $grey-dk-300 !important;
+}
+
+.text-grey-lt-000 {
+  color: $grey-lt-000 !important;
+}
+
+.text-grey-lt-100 {
+  color: $grey-lt-100 !important;
+}
+
+.text-grey-lt-200 {
+  color: $grey-lt-200 !important;
+}
+
+.text-grey-lt-300 {
+  color: $grey-lt-300 !important;
+}
+
+.text-blue-000 {
+  color: $blue-000 !important;
+}
+
+.text-blue-100 {
+  color: $blue-100 !important;
+}
+
+.text-blue-200 {
+  color: $blue-200 !important;
+}
+
+.text-blue-300 {
+  color: $blue-300 !important;
+}
+
+.text-green-000 {
+  color: $green-000 !important;
+}
+
+.text-green-100 {
+  color: $green-100 !important;
+}
+
+.text-green-200 {
+  color: $green-200 !important;
+}
+
+.text-green-300 {
+  color: $green-300 !important;
+}
+
+.text-purple-000 {
+  color: $purple-000 !important;
+}
+
+.text-purple-100 {
+  color: $purple-100 !important;
+}
+
+.text-purple-200 {
+  color: $purple-200 !important;
+}
+
+.text-purple-300 {
+  color: $purple-300 !important;
+}
+
+.text-yellow-000 {
+  color: $yellow-000 !important;
+}
+
+.text-yellow-100 {
+  color: $yellow-100 !important;
+}
+
+.text-yellow-200 {
+  color: $yellow-200 !important;
+}
+
+.text-yellow-300 {
+  color: $yellow-300 !important;
+}
+
+.text-red-000 {
+  color: $red-000 !important;
+}
+
+.text-red-100 {
+  color: $red-100 !important;
+}
+
+.text-red-200 {
+  color: $red-200 !important;
+}
+
+.text-red-300 {
+  color: $red-300 !important;
+}
+
+// Background colors
+
+.bg-grey-dk-000 {
+  background-color: $grey-dk-000 !important;
+}
+
+.bg-grey-dk-100 {
+  background-color: $grey-dk-100 !important;
+}
+
+.bg-grey-dk-200 {
+  background-color: $grey-dk-200 !important;
+}
+
+.bg-grey-dk-250 {
+  background-color: $grey-dk-250 !important;
+}
+
+.bg-grey-dk-300 {
+  background-color: $grey-dk-300 !important;
+}
+
+.bg-grey-lt-000 {
+  background-color: $grey-lt-000 !important;
+}
+
+.bg-grey-lt-100 {
+  background-color: $grey-lt-100 !important;
+}
+
+.bg-grey-lt-200 {
+  background-color: $grey-lt-200 !important;
+}
+
+.bg-grey-lt-300 {
+  background-color: $grey-lt-300 !important;
+}
+
+.bg-blue-000 {
+  background-color: $blue-000 !important;
+}
+
+.bg-blue-100 {
+  background-color: $blue-100 !important;
+}
+
+.bg-blue-200 {
+  background-color: $blue-200 !important;
+}
+
+.bg-blue-300 {
+  background-color: $blue-300 !important;
+}
+
+.bg-green-000 {
+  background-color: $green-000 !important;
+}
+
+.bg-green-100 {
+  background-color: $green-100 !important;
+}
+
+.bg-green-200 {
+  background-color: $green-200 !important;
+}
+
+.bg-green-300 {
+  background-color: $green-300 !important;
+}
+
+.bg-purple-000 {
+  background-color: $purple-000 !important;
+}
+
+.bg-purple-100 {
+  background-color: $purple-100 !important;
+}
+
+.bg-purple-200 {
+  background-color: $purple-200 !important;
+}
+
+.bg-purple-300 {
+  background-color: $purple-300 !important;
+}
+
+.bg-yellow-000 {
+  background-color: $yellow-000 !important;
+}
+
+.bg-yellow-100 {
+  background-color: $yellow-100 !important;
+}
+
+.bg-yellow-200 {
+  background-color: $yellow-200 !important;
+}
+
+.bg-yellow-300 {
+  background-color: $yellow-300 !important;
+}
+
+.bg-red-000 {
+  background-color: $red-000 !important;
+}
+
+.bg-red-100 {
+  background-color: $red-100 !important;
+}
+
+.bg-red-200 {
+  background-color: $red-200 !important;
+}
+
+.bg-red-300 {
+  background-color: $red-300 !important;
+}
diff --git a/docs/_sass/utilities/_layout.scss b/docs/_sass/utilities/_layout.scss
new file mode 100644
index 0000000..01a57c5
--- /dev/null
+++ b/docs/_sass/utilities/_layout.scss
@@ -0,0 +1,101 @@
+// Utility classes for layout
+
+// Display
+
+.d-block {
+  display: block !important;
+}
+
+.d-flex {
+  display: flex !important;
+}
+
+.d-inline {
+  display: inline !important;
+}
+
+.d-inline-block {
+  display: inline-block !important;
+}
+
+.d-none {
+  display: none !important;
+}
+
+@each $media-query in map-keys($media-queries) {
+  @for $i from 1 through length($spacers) {
+    @include mq($media-query) {
+      $size: #{map-get($spacers, sp-#{$i - 1})};
+      $scale: #{$i - 1};
+
+      // .d-sm-block, .d-md-none, .d-lg-inline
+      .d-#{$media-query}-block {
+        display: block !important;
+      }
+      .d-#{$media-query}-flex {
+        display: flex !important;
+      }
+      .d-#{$media-query}-inline {
+        display: inline !important;
+      }
+      .d-#{$media-query}-inline-block {
+        display: inline-block !important;
+      }
+      .d-#{$media-query}-none {
+        display: none !important;
+      }
+    }
+  }
+}
+
+// Horizontal alignment
+
+.float-left {
+  float: left !important;
+}
+
+.float-right {
+  float: right !important;
+}
+
+.flex-justify-start {
+  justify-content: flex-start !important;
+}
+
+.flex-justify-end {
+  justify-content: flex-end !important;
+}
+
+.flex-justify-between {
+  justify-content: space-between !important;
+}
+
+.flex-justify-around {
+  justify-content: space-around !important;
+}
+
+// Vertical alignment
+
+.v-align-baseline {
+  vertical-align: baseline !important;
+}
+
+.v-align-bottom {
+  vertical-align: bottom !important;
+}
+
+.v-align-middle {
+  vertical-align: middle !important;
+}
+
+.v-align-text-bottom {
+  vertical-align: text-bottom !important;
+}
+
+.v-align-text-top {
+  vertical-align: text-top !important;
+}
+
+.v-align-top {
+  vertical-align: top !important;
+}
diff --git a/docs/_sass/utilities/_lists.scss b/docs/_sass/utilities/_lists.scss
new file mode 100644
index 0000000..3adc421
--- /dev/null
+++ b/docs/_sass/utilities/_lists.scss
@@ -0,0 +1,15 @@
+// Utility classes for lists
+
+// stylelint-disable selector-max-type
+
+.list-style-none {
+  padding: 0 !important;
+  margin: 0 !important;
+  list-style: none !important;
+
+  li {
+    &::before {
+      display: none !important;
+    }
+  }
+}
diff --git a/docs/_sass/utilities/_spacing.scss b/docs/_sass/utilities/_spacing.scss
new file mode 100644
index 0000000..a811861
--- /dev/null
+++ b/docs/_sass/utilities/_spacing.scss
@@ -0,0 +1,162 @@
+// Utility classes for margins and padding
+
+// stylelint-disable block-opening-brace-space-after, block-opening-brace-space-before
+
+// Margin spacer utilities
+
+.mx-auto {
+  margin-right: auto !important;
+  margin-left: auto !important;
+}
+
+@for $i from 1 through length($spacers) {
+  $size: #{map-get($spacers, sp-#{$i - 1})};
+  $scale: #{$i - 1};
+
+  // .m-0, .m-1, .m-2...
+  .m-#{$scale} {
+    margin: #{$size} !important;
+  }
+  .mt-#{$scale} {
+    margin-top: #{$size} !important;
+  }
+  .mr-#{$scale} {
+    margin-right: #{$size} !important;
+  }
+  .mb-#{$scale} {
+    margin-bottom: #{$size} !important;
+  }
+  .ml-#{$scale} {
+    margin-left: #{$size} !important;
+  }
+
+  .mx-#{$scale} {
+    margin-right: #{$size} !important;
+    margin-left: #{$size} !important;
+  }
+
+  .my-#{$scale} {
+    margin-top: #{$size} !important;
+    margin-bottom: #{$size} !important;
+  }
+
+  .mxn-#{$scale} {
+    margin-right: -#{$size} !important;
+    margin-left: -#{$size} !important;
+  }
+  .mx-#{$scale}-auto {
+    margin-right: auto !important;
+    margin-left: auto !important;
+  }
+}
+
+@each $media-query in map-keys($media-queries) {
+  @for $i from 1 through length($spacers) {
+    @include mq($media-query) {
+      $size: #{map-get($spacers, sp-#{$i - 1})};
+      $scale: #{$i - 1};
+
+      // .m-sm-0, .m-md-1, .m-lg-2...
+      .m-#{$media-query}-#{$scale} {
+        margin: #{$size} !important;
+      }
+      .mt-#{$media-query}-#{$scale} {
+        margin-top: #{$size} !important;
+      }
+      .mr-#{$media-query}-#{$scale} {
+        margin-right: #{$size} !important;
+      }
+      .mb-#{$media-query}-#{$scale} {
+        margin-bottom: #{$size} !important;
+      }
+      .ml-#{$media-query}-#{$scale} {
+        margin-left: #{$size} !important;
+      }
+
+      .mx-#{$media-query}-#{$scale} {
+        margin-right: #{$size} !important;
+        margin-left: #{$size} !important;
+      }
+
+      .my-#{$media-query}-#{$scale} {
+        margin-top: #{$size} !important;
+        margin-bottom: #{$size} !important;
+      }
+
+      .mxn-#{$media-query}-#{$scale} {
+        margin-right: -#{$size} !important;
+        margin-left: -#{$size} !important;
+      }
+    }
+  }
+}
+
+// Padding spacer utilities
+
+@for $i from 1 through length($spacers) {
+  $size: #{map-get($spacers, sp-#{$i - 1})};
+  $scale: #{$i - 1};
+
+  // .p-0, .p-1, .p-2...
+  .p-#{$scale} {
+    padding: #{$size} !important;
+  }
+  .pt-#{$scale} {
+    padding-top: #{$size} !important;
+  }
+  .pr-#{$scale} {
+    padding-right: #{$size} !important;
+  }
+  .pb-#{$scale} {
+    padding-bottom: #{$size} !important;
+  }
+  .pl-#{$scale} {
+    padding-left: #{$size} !important;
+  }
+
+  .px-#{$scale} {
+    padding-right: #{$size} !important;
+    padding-left: #{$size} !important;
+  }
+
+  .py-#{$scale} {
+    padding-top: #{$size} !important;
+    padding-bottom: #{$size} !important;
+  }
+}
+
+@each $media-query in map-keys($media-queries) {
+  @include mq($media-query) {
+    @for $i from 1 through length($spacers) {
+      $size: #{map-get($spacers, sp-#{$i - 1})};
+      $scale: #{$i - 1};
+
+      // .p-sm-0, .p-md-1, .p-lg-2...
+      .p-#{$media-query}-#{$scale} {
+        padding: #{$size} !important;
+      }
+      .pt-#{$media-query}-#{$scale} {
+        padding-top: #{$size} !important;
+      }
+      .pr-#{$media-query}-#{$scale} {
+        padding-right: #{$size} !important;
+      }
+      .pb-#{$media-query}-#{$scale} {
+        padding-bottom: #{$size} !important;
+      }
+      .pl-#{$media-query}-#{$scale} {
+        padding-left: #{$size} !important;
+      }
+
+      .px-#{$media-query}-#{$scale} {
+        padding-right: #{$size} !important;
+        padding-left: #{$size} !important;
+      }
+
+      .py-#{$media-query}-#{$scale} {
+        padding-top: #{$size} !important;
+        padding-bottom: #{$size} !important;
+      }
+    }
+  }
+}
diff --git a/docs/_sass/utilities/_typography.scss b/docs/_sass/utilities/_typography.scss
new file mode 100644
index 0000000..33f1db9
--- /dev/null
+++ b/docs/_sass/utilities/_typography.scss
@@ -0,0 +1,85 @@
+// Utility classes for typography
+
+.fs-1 {
+  @include fs-1;
+}
+
+.fs-2 {
+  @include fs-2;
+}
+
+.fs-3 {
+  @include fs-3;
+}
+
+.fs-4 {
+  @include fs-4;
+}
+
+.fs-5 {
+  @include fs-5;
+}
+
+.fs-6 {
+  @include fs-6;
+}
+
+.fs-7 {
+  @include fs-7;
+}
+
+.fs-8 {
+  @include fs-8;
+}
+
+.fs-9 {
+  @include fs-9;
+}
+
+.fs-10 {
+  @include fs-10;
+}
+
+.fw-300 {
+  font-weight: 300 !important;
+}
+
+.fw-400 {
+  font-weight: 400 !important;
+}
+
+.fw-500 {
+  font-weight: 500 !important;
+}
+
+.fw-700 {
+  font-weight: 700 !important;
+}
+
+.lh-0 {
+  line-height: 0 !important;
+}
+
+.lh-default {
+  line-height: $body-line-height;
+}
+
+.lh-tight {
+  line-height: $body-heading-line-height;
+}
+
+.ls-5 {
+  letter-spacing: 0.05em !important;
+}
+
+.ls-10 {
+  letter-spacing: 0.1em !important;
+}
+
+.ls-0 {
+  letter-spacing: 0 !important;
+}
+
+.text-uppercase {
+  text-transform: uppercase !important;
+}
diff --git a/docs/_sass/utilities/utilities.scss b/docs/_sass/utilities/utilities.scss
new file mode 100644
index 0000000..6c25bdf
--- /dev/null
+++ b/docs/_sass/utilities/utilities.scss
@@ -0,0 +1,5 @@
+@import "./colors";
+@import "./layout";
+@import "./typography";
+@import "./lists";
+@import "./spacing";
diff --git a/docs/_sass/vendor/OneDarkJekyll/LICENSE b/docs/_sass/vendor/OneDarkJekyll/LICENSE
new file mode 100644
index 0000000..01d0dfb
--- /dev/null
+++ b/docs/_sass/vendor/OneDarkJekyll/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 Mihály Gyöngyösi
+
+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.
diff --git a/docs/_sass/vendor/OneDarkJekyll/syntax.scss b/docs/_sass/vendor/OneDarkJekyll/syntax.scss
new file mode 100644
index 0000000..3888797
--- /dev/null
+++ b/docs/_sass/vendor/OneDarkJekyll/syntax.scss
@@ -0,0 +1,202 @@
+// Generated with OneDarkJekyll applied to Atom's One Dark Vivid theme
+
+.highlight,
+pre.highlight {
+  background: #31343f;
+  color: #dee2f7;
+}
+.highlight pre {
+  background: #31343f;
+}
+.highlight .hll {
+  background: #31343f;
+}
+.highlight .c {
+  color: #63677e;
+  font-style: italic;
+}
+.highlight .err {
+  color: #960050;
+  background-color: #1e0010;
+}
+.highlight .k {
+  color: #e19ef5;
+}
+.highlight .l {
+  color: #a3eea0;
+}
+.highlight .n {
+  color: #dee2f7;
+}
+.highlight .o {
+  color: #dee2f7;
+}
+.highlight .p {
+  color: #dee2f7;
+}
+.highlight .cm {
+  color: #63677e;
+  font-style: italic;
+}
+.highlight .cp {
+  color: #63677e;
+  font-style: italic;
+}
+.highlight .c1 {
+  color: #63677e;
+  font-style: italic;
+}
+.highlight .cs {
+  color: #63677e;
+  font-style: italic;
+}
+.highlight .ge {
+  font-style: italic;
+}
+.highlight .gs {
+  font-weight: 700;
+}
+.highlight .kc {
+  color: #e19ef5;
+}
+.highlight .kd {
+  color: #e19ef5;
+}
+.highlight .kn {
+  color: #e19ef5;
+}
+.highlight .kp {
+  color: #e19ef5;
+}
+.highlight .kr {
+  color: #e19ef5;
+}
+.highlight .kt {
+  color: #e19ef5;
+}
+.highlight .ld {
+  color: #a3eea0;
+}
+.highlight .m {
+  color: #eddc96;
+}
+.highlight .s {
+  color: #a3eea0;
+}
+.highlight .na {
+  color: #eddc96;
+}
+.highlight .nb {
+  color: #fdce68;
+}
+.highlight .nc {
+  color: #fdce68;
+}
+.highlight .no {
+  color: #fdce68;
+}
+.highlight .nd {
+  color: #fdce68;
+}
+.highlight .ni {
+  color: #fdce68;
+}
+.highlight .ne {
+  color: #fdce68;
+}
+.highlight .nf {
+  color: #dee2f7;
+}
+.highlight .nl {
+  color: #fdce68;
+}
+.highlight .nn {
+  color: #dee2f7;
+}
+.highlight .nx {
+  color: #dee2f7;
+}
+.highlight .py {
+  color: #fdce68;
+}
+.highlight .nt {
+  color: #f9867b;
+}
+.highlight .nv {
+  color: #fdce68;
+}
+.highlight .ow {
+  font-weight: 700;
+}
+.highlight .w {
+  color: #f8f8f2;
+}
+.highlight .mf {
+  color: #eddc96;
+}
+.highlight .mh {
+  color: #eddc96;
+}
+.highlight .mi {
+  color: #eddc96;
+}
+.highlight .mo {
+  color: #eddc96;
+}
+.highlight .sb {
+  color: #a3eea0;
+}
+.highlight .sc {
+  color: #a3eea0;
+}
+.highlight .sd {
+  color: #a3eea0;
+}
+.highlight .s2 {
+  color: #a3eea0;
+}
+.highlight .se {
+  color: #a3eea0;
+}
+.highlight .sh {
+  color: #a3eea0;
+}
+.highlight .si {
+  color: #a3eea0;
+}
+.highlight .sx {
+  color: #a3eea0;
+}
+.highlight .sr {
+  color: #7be2f9;
+}
+.highlight .s1 {
+  color: #a3eea0;
+}
+.highlight .ss {
+  color: #7be2f9;
+}
+.highlight .bp {
+  color: #fdce68;
+}
+.highlight .vc {
+  color: #fdce68;
+}
+.highlight .vg {
+  color: #fdce68;
+}
+.highlight .vi {
+  color: #f9867b;
+}
+.highlight .il {
+  color: #eddc96;
+}
+.highlight .gu {
+  color: #75715e;
+}
+.highlight .gd {
+  color: #f92672;
+}
+.highlight .gi {
+  color: #a6e22e;
+}
diff --git a/docs/_sass/vendor/OneLightJekyll/LICENSE b/docs/_sass/vendor/OneLightJekyll/LICENSE
new file mode 100644
index 0000000..df5eca0
--- /dev/null
+++ b/docs/_sass/vendor/OneLightJekyll/LICENSE
@@ -0,0 +1,65 @@
+OneLightJekyll relies on two works: OneDarkJekyll, and Atom's One Light theme. This file contains the licensing for all the related software.
+
+---
+
+OneLightJekyll (https://github.com/just-the-docs/OneLightJekyll/blob/main/LICENSE)
+
+MIT License
+
+Copyright (c) 2023 Matthew Wang
+
+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.
+
+---
+
+OneDarkJekyll (https://github.com/mgyongyosi/OneDarkJekyll/blob/master/LICENSE)
+
+MIT License
+
+Copyright (c) 2016 Mihály Gyöngyösi
+
+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.
+
+---
+
+Atom One Light (https://github.com/atom/atom/blob/master/LICENSE.md)
+
+Copyright (c) 2011-2022 GitHub Inc.
+
+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.
diff --git a/docs/_sass/vendor/OneLightJekyll/syntax.scss b/docs/_sass/vendor/OneLightJekyll/syntax.scss
new file mode 100644
index 0000000..674b7f8
--- /dev/null
+++ b/docs/_sass/vendor/OneLightJekyll/syntax.scss
@@ -0,0 +1,208 @@
+// Generated with OneLightJekyll applied to Atom's One Light theme
+
+.highlight,
+pre.highlight {
+  background: #f9f9f9;
+  color: #383942;
+}
+.highlight pre {
+  background: #f9f9f9;
+}
+.highlight .hll {
+  background: #f9f9f9;
+}
+.highlight .c {
+  color: #9fa0a6;
+  font-style: italic;
+}
+.highlight .err {
+  color: #fff;
+  background-color: #e05151;
+}
+.highlight .k {
+  color: #a625a4;
+}
+.highlight .l {
+  color: #50a04f;
+}
+.highlight .n {
+  color: #383942;
+}
+.highlight .o {
+  color: #383942;
+}
+.highlight .p {
+  color: #383942;
+}
+.highlight .cm {
+  color: #9fa0a6;
+  font-style: italic;
+}
+.highlight .cp {
+  color: #9fa0a6;
+  font-style: italic;
+}
+.highlight .c1 {
+  color: #9fa0a6;
+  font-style: italic;
+}
+.highlight .cs {
+  color: #9fa0a6;
+  font-style: italic;
+}
+.highlight .ge {
+  font-style: italic;
+}
+.highlight .gs {
+  font-weight: 700;
+}
+.highlight .kc {
+  color: #a625a4;
+}
+.highlight .kd {
+  color: #a625a4;
+}
+.highlight .kn {
+  color: #a625a4;
+}
+.highlight .kp {
+  color: #a625a4;
+}
+.highlight .kr {
+  color: #a625a4;
+}
+.highlight .kt {
+  color: #a625a4;
+}
+.highlight .ld {
+  color: #50a04f;
+}
+.highlight .m {
+  color: #b66a00;
+}
+.highlight .s {
+  color: #50a04f;
+}
+.highlight .na {
+  color: #b66a00;
+}
+.highlight .nb {
+  color: #ca7601;
+}
+.highlight .nc {
+  color: #ca7601;
+}
+.highlight .no {
+  color: #ca7601;
+}
+.highlight .nd {
+  color: #ca7601;
+}
+.highlight .ni {
+  color: #ca7601;
+}
+.highlight .ne {
+  color: #ca7601;
+}
+.highlight .nf {
+  color: #383942;
+}
+.highlight .nl {
+  color: #ca7601;
+}
+.highlight .nn {
+  color: #383942;
+}
+.highlight .nx {
+  color: #383942;
+}
+.highlight .py {
+  color: #ca7601;
+}
+.highlight .nt {
+  color: #e35549;
+}
+.highlight .nv {
+  color: #ca7601;
+}
+.highlight .ow {
+  font-weight: 700;
+}
+.highlight .w {
+  color: #f8f8f2;
+}
+.highlight .mf {
+  color: #b66a00;
+}
+.highlight .mh {
+  color: #b66a00;
+}
+.highlight .mi {
+  color: #b66a00;
+}
+.highlight .mo {
+  color: #b66a00;
+}
+.highlight .sb {
+  color: #50a04f;
+}
+.highlight .sc {
+  color: #50a04f;
+}
+.highlight .sd {
+  color: #50a04f;
+}
+.highlight .s2 {
+  color: #50a04f;
+}
+.highlight .se {
+  color: #50a04f;
+}
+.highlight .sh {
+  color: #50a04f;
+}
+.highlight .si {
+  color: #50a04f;
+}
+.highlight .sx {
+  color: #50a04f;
+}
+.highlight .sr {
+  color: #0083bb;
+}
+.highlight .s1 {
+  color: #50a04f;
+}
+.highlight .ss {
+  color: #0083bb;
+}
+.highlight .bp {
+  color: #ca7601;
+}
+.highlight .vc {
+  color: #ca7601;
+}
+.highlight .vg {
+  color: #ca7601;
+}
+.highlight .vi {
+  color: #e35549;
+}
+.highlight .il {
+  color: #b66a00;
+}
+.highlight .gu {
+  color: #75715e;
+}
+.highlight .gd {
+  color: #e05151;
+}
+.highlight .gi {
+  color: #43d089;
+}
+.highlight .language-json .w + .s2 {
+  color: #e35549;
+}
+.highlight .language-json .kc {
+  color: #0083bb;
+}
diff --git a/docs/_sass/vendor/normalize.scss/README.md b/docs/_sass/vendor/normalize.scss/README.md
new file mode 100644
index 0000000..7af1714
--- /dev/null
+++ b/docs/_sass/vendor/normalize.scss/README.md
@@ -0,0 +1,7 @@
+# normalize.scss
+
+Normalize.scss is an SCSS copy of [normalize.css](http://necolas.github.io/normalize.css), a customisable CSS file that makes browsers render all elements more consistently and in line with modern standards.
+
+The [normalize.scss fork](https://github.com/guerrero/normalize.scss) of [normalize.css](http://necolas.github.io/normalize.css) was archived in 2014, and has not been updated since v0.1.0.
+
+[View the normalize.css test file](http://necolas.github.io/normalize.css/latest/test.html)
diff --git a/docs/_sass/vendor/normalize.scss/normalize.scss b/docs/_sass/vendor/normalize.scss/normalize.scss
new file mode 100644
index 0000000..bb6e2a7
--- /dev/null
+++ b/docs/_sass/vendor/normalize.scss/normalize.scss
@@ -0,0 +1,351 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+   ========================================================================== */
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+html {
+  line-height: 1.15; /* 1 */
+  -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+   ========================================================================== */
+
+/**
+ * Remove the margin in all browsers.
+ */
+
+body {
+  margin: 0;
+}
+
+/**
+ * Render the `main` element consistently in IE.
+ */
+
+main {
+  display: block;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+
+/* Grouping content
+   ========================================================================== */
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+  box-sizing: content-box; /* 1 */
+  height: 0; /* 1 */
+  overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+  font-family: monospace, monospace; /* 1 */
+  font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+   ========================================================================== */
+
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+
+a {
+  background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+  border-bottom: none; /* 1 */
+  text-decoration: underline; /* 2 */
+  text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+  font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+  font-family: monospace, monospace; /* 1 */
+  font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+  font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+sup {
+  top: -0.5em;
+}
+
+/* Embedded content
+   ========================================================================== */
+
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+
+img {
+  border-style: none;
+}
+
+/* Forms
+   ========================================================================== */
+
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+  font-family: inherit; /* 1 */
+  font-size: 100%; /* 1 */
+  line-height: 1.15; /* 1 */
+  margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input {
+  /* 1 */
+  overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select {
+  /* 1 */
+  text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+  -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+  border-style: none;
+  padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+  outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+
+fieldset {
+  padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ *    `fieldset` elements in all browsers.
+ */
+
+legend {
+  box-sizing: border-box; /* 1 */
+  color: inherit; /* 2 */
+  display: table; /* 1 */
+  max-width: 100%; /* 1 */
+  padding: 0; /* 3 */
+  white-space: normal; /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+  vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+textarea {
+  overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+  box-sizing: border-box; /* 1 */
+  padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+  -webkit-appearance: textfield; /* 1 */
+  outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+  -webkit-appearance: button; /* 1 */
+  font: inherit; /* 2 */
+}
+
+/* Interactive
+   ========================================================================== */
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+  display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+  display: list-item;
+}
+
+/* Misc
+   ========================================================================== */
+
+/**
+ * Add the correct display in IE 10+.
+ */
+
+template {
+  display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+  display: none;
+}
diff --git a/docs/commands/index.md b/docs/commands/index.md
new file mode 100644
index 0000000..151a2e5
--- /dev/null
+++ b/docs/commands/index.md
@@ -0,0 +1,69 @@
+---
+layout: default
+nav_order: 3
+# permalink: /
+# parent: Home
+permalink: /commands
+title: Custom Commands
+markdown: Kramdown
+has_children: true
+kramdown:
+  parse_block_html: true
+  auto_ids: true
+  syntax_highlighter: coderay
+---
+
+<button class="btn js-toggle-dark-mode">Switch to Dark Mode
+
+<script>
+const toggleDarkMode = document.querySelector('.js-toggle-dark-mode');
+
+jtd.addEvent(toggleDarkMode, 'click', function(){
+  if (jtd.getTheme() === 'dark') {
+    jtd.setTheme('light');
+    toggleDarkMode.textContent = 'Switch to Dark Mode';
+  } else {
+    jtd.setTheme('dark');
+    toggleDarkMode.textContent = 'Switch to Light Mode';
+  }
+});
+</script>
+
+# Custom Commands
+{: .fs-9 }
+
+Create monitoring dasboards on the terminal easily with a simple yaml file !
+
+<br>
+
+## Examples
+- [pods.yml](../../examples/dashboards/pods.yml)
+- [pvcs.yml](../../examples/dashboards/pvcs.yml)
+
+<br>
+
+---
+
+<br>
+
+## List commands
+
+```bash
+kptop --list-commands
+```
+
+
+## Run command
+
+
+```bash
+kptop --command <DASHBOARD-NAME>
+```
+
+<br>
+
+---
+
+## Command YAMl structure
+
+To be added.
diff --git a/docs/css/custom.css b/docs/css/custom.css
new file mode 100644
index 0000000..0dfa61c
--- /dev/null
+++ b/docs/css/custom.css
@@ -0,0 +1,91 @@
+body .gist .highlight {
+    background: #293134;
+}
+body .gist .blob-num,
+body .gist .blob-code-inner,
+body .gist .pl-ent,
+body .gist .pl-s1,
+body .gist .pl-s1 .pl-s2,
+body .gist .pl-smi,
+body .gist .pl-smp,
+body .gist .pl-stj,
+body .gist .pl-vo,
+body .gist .pl-vpf {
+    color: #e0e2e4;
+}
+body .gist .pl-c,
+body .gist .pl-c span {
+    color: #66747b;
+    font-style: italic;
+}
+body .gist .pl-mb {
+    color: #ec7600;
+    font-weight: 700;
+}
+body .gist .pl-mh .pl-en {
+    color: #66747b;
+    font-weight: 700;
+}
+body .gist .pl-mi {
+    color: #93c763;
+    font-style: italic;
+}
+body .gist .pl-sc {
+    color: #96989a;
+}
+body .gist .pl-st {
+    color: #da4236;
+}
+body .gist .pl-c1>.pl-c1 {
+    color: #678cb1;
+}
+body .gist .pl-c1,
+body .gist .pl-sr .pl-cce {
+    color: #ffcd22;
+}
+body .gist .pl-e,
+body .gist .pl-k,
+body .gist .pl-mdh,
+body .gist .pl-mdr,
+body .gist .pl-ml,
+body .gist .pl-mm,
+body .gist .pl-mo,
+body .gist .pl-mp,
+body .gist .pl-mr,
+body .gist .pl-ms,
+body .gist .pl-s1 .pl-v,
+body .gist .pl-s3 {
+    color: #93c763;
+}
+body .gist .pl-en,
+body .gist .pl-v {
+    color: #65acf3;
+}
+body .gist .pl-mh,
+body .gist .pl-mq {
+    color: #448eb4;
+}
+body .gist .pl-pds,
+body .gist .pl-s,
+body .gist .pl-s1 .pl-pse .pl-s2,
+body .gist .pl-sv {
+    color: #ec7600;
+}
+body .gist .pl-sr,
+body .gist .pl-sr .pl-sra,
+body .gist .pl-sr .pl-sre,
+body .gist .pl-src {
+    color: #d39745;
+}
+body .gist .pl-mi1,
+body .gist .pl-mdht {
+    color: #e0e2e4;
+    background: rgba(0, 64, 0, .5);
+}
+body .gist .pl-md,
+body .gist .pl-mdhf,
+body .gist .pl-id,
+body .gist .pl-ii {
+    color: #e0e2e4;
+    background: rgba(64, 0, 0, .5);
+}
\ No newline at end of file
diff --git a/docs/dashboards/index.md b/docs/dashboards/index.md
new file mode 100644
index 0000000..dd89122
--- /dev/null
+++ b/docs/dashboards/index.md
@@ -0,0 +1,69 @@
+---
+layout: default
+nav_order: 2
+# permalink: /
+# parent: Home
+permalink: /dashboards
+title: Custom Dashboards
+markdown: Kramdown
+has_children: true
+kramdown:
+  parse_block_html: true
+  auto_ids: true
+  syntax_highlighter: coderay
+---
+
+<button class="btn js-toggle-dark-mode">Switch to Dark Mode
+
+<script>
+const toggleDarkMode = document.querySelector('.js-toggle-dark-mode');
+
+jtd.addEvent(toggleDarkMode, 'click', function(){
+  if (jtd.getTheme() === 'dark') {
+    jtd.setTheme('light');
+    toggleDarkMode.textContent = 'Switch to Dark Mode';
+  } else {
+    jtd.setTheme('dark');
+    toggleDarkMode.textContent = 'Switch to Light Mode';
+  }
+});
+</script>
+
+# Custom Dashboards
+{: .fs-9 }
+
+Create monitoring dasboards on the terminal easily with a simple yaml file !
+
+<br>
+
+## Examples
+- [pods.yml](../../examples/dashboards/pods.yml)
+- [pvcs.yml](../../examples/dashboards/pvcs.yml)
+
+<br>
+
+---
+
+<br>
+
+## List dashboards
+
+```bash
+kptop --list-dashboards
+```
+
+
+## Run dashboard
+
+
+```bash
+kptop --dashboard <DASHBOARD-NAME>
+```
+
+<br>
+
+---
+
+## Dashboard YAMl structure
+
+To be added.
diff --git a/docs/images/dashboard-pods.png b/docs/images/dashboard-pods.png
new file mode 100644
index 0000000..697f941
Binary files /dev/null and b/docs/images/dashboard-pods.png differ
diff --git a/docs/images/dashboard-pvcs.png b/docs/images/dashboard-pvcs.png
new file mode 100644
index 0000000..674899c
Binary files /dev/null and b/docs/images/dashboard-pvcs.png differ
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..325aaff
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,246 @@
+---
+# default, page
+layout: default
+# nav_order: 0
+# description: KPtop Documentation
+# permalink: /
+# title: Home
+# has_children: false
+markdown: Kramdown
+kramdown:
+  parse_block_html: true
+  auto_ids: false
+  syntax_highlighter: coderay
+---
+
+# Kube-Prometheus-Top [ KPtop ]
+{: .fs-9 }
+
+<br>
+
+A Python tool that offers beautiful CLI monitoring based on Prometheus metrics, with Kubernetes integration through PodPortForward
+
+Allowing you to create your own custom CLI dashboards & CLI commands with custom layouts, variables, CLI arguments !
+
+<br>
+
+# Motivation
+Prometheus is widely used with different kinds of metrics - Let's make CLI monitoring more powerful with Prometheus data.
+
+
+
+<br>
+
+---
+
+
+## Environment Variables
+<a id=env></a>
+
+| ENV | Description                                                                          | Default | Required |
+| ----- | -------------------------------------------------------------------------------------- | --------- | ---------- |
+| `KPTOP_CONNECTION_METHOD`    | The way to connect to Prometheus server<br />**options:** ['`prometheus_endpoint`', '`pod_portForward`'] | <br />      | Yes      |
+
+There are 2 options to connect KPtop to Prometheus:
+1. With a Prometheus server endpoint
+    - Suitable if Prometheus is exposed (with an ingress for example)
+2. With 'K8s pod port-forward' (Through K8s API-Server)
+    - Suitable if Prometheus is Not exposed (Only rechable with K8s cluster access)
+
+
+### `prometheus_endpoint` ENVs
+
+| ENV | Description                                                     | Default | Required |
+| ----- | ----------------------------------------------------------------- | --------- | ---------- |
+| `KPTOP_PROMETHEUS_SERVER`    | Prometheus server URL                                           |         | Yes      |
+| `KPTOP_BASIC_AUTH_ENABLED`    | Whether basic authentication is needed to connect to Prometheus | False   | No       |
+| `KPTOP_PROMETHEUS_USERNAME`    | Prometheus username                                             |         | No       |
+| `KPTOP_PROMETHEUS_PASSWORD`    | Prometheus password                                             |         | No       |
+| `KPTOP_INSECURE`    | Verify SSL certificate                                          | False   | No       |
+
+
+<br>
+
+### `pod_portForward` ENVs
+
+| ENV | Description                                            | Default | Required |
+| ----- | -------------------------------------------------------- | --------- | ---------- |
+| `KPTOP_PROMETHEUS_POD_NAME`    | Prometheus pod name                                    |         | Yes      |
+| `KPTOP_PROMETHEUS_POD_PORT`    | Prometheus port number                                 | 9090    | No       |
+| `KPTOP_PROMETHEUS_POD_NAMESPACE`    | The name space in which the Prometheus pod is deployed | default | No       |
+| `KUBECONFIG`    | custom K8s kube config file                            | *default path*        | No       |
+
+
+<br>
+
+### General ENVs
+
+| ENV                                  | Description                                                  | Default               | Required |
+| ------------------------------------ | ------------------------------------------------------------ | --------------------- | -------- |
+| `KPTOP_START_GRAPHS_WITH_ZERO`       | By default graphs begin with '0'  to let the graph take its full hight | True                  | NO       |
+| `KPTOP_LOGGING_DIR`                  | Choose a different logging directory                         | /tmp/                 | NO       |
+| `KPTOP_GRAPH_WIDTH`                  | Choose a custom graphs width                                 | 45                    | NO       |
+| `KPTOP_DEFAULT_DASHBOARDS_DIRECTORY` | Default directory contains the dashboards yaml files         | /var/kptop/dashboards | NO       |
+| `KPTOP_DEFAULT_COMMANDS_DIRECTORY`   | Default directory contains the commands yaml files           | /var/kptop/commands   | NO       |
+
+
+
+<br>
+
+---
+
+# CLI Arguments
+<a id=cli></a>
+
+
+| ENV                         | Description                                                  |
+| --------------------------- | ------------------------------------------------------------ |
+| `--dashboard` , `-D`        | Specify a dashboard YAML file                                |
+| `--command` , `-C`          | Specify a command YAML file                                  |
+| `--list-dashboards` , `-ld` | List all the available dashboards                            |
+| `--list-commands` , `-lc`   | List all the available commands                              |
+| `--debug`,  `-d`            | Enable debugging logging mode                                |
+| `--version`,  `-V`          | Show kptop version                                           |
+| `--print-layout`,  `-pl`    | Print the dashboard empty layout                             |
+| `--vhelp` ,  `-vh`          | Print the arguments including "the variables arguments defined in your command yaml file" |
+
+
+<br>
+
+---
+
+
+# Usage
+
+
+## [1] Add the Prometheus connection Environment Variables
+
+## Example
+
+<br>
+
+Add the ENVs and you're good to go.
+
+_*Examples*_
+
+```bash
+export KPTOP_CONNECTION_METHOD="pod_portForward"
+export KPTOP_PROMETHEUS_POD_NAME="my-prometheus-server-0"
+export KPTOP_PROMETHEUS_POD_PORT="9090"
+export KPTOP_PROMETHEUS_POD_NAMESPACE="monitoring"
+```
+
+> Or
+
+```bash
+export KPTOP_CONNECTION_METHOD="prometheus_endpoint"
+export KPTOP_PROMETHEUS_SERVER="http://prometheus.home-lab.com"
+```
+
+
+<br>
+
+## [2] Configure the location of your dashboards & commands
+
+
+Example:
+
+```bash
+export KPTOP_DEFAULT_DASHBOARDS_DIRECTORY="/Users/YOU/kptop/examples/dashboards"
+export KPTOP_DEFAULT_COMMANDS_DIRECTORY="/Users/YOU/kptop/examples/dashboards"
+```
+
+
+
+## Run dashboards / commands !
+
+### [Dashboards Doc](./dashboards/)
+### [Commands Doc](./commands/)
+
+
+```bash
+kptop --list-dashboards
+```
+
+```
+DASHBOARD      CREATION TIME        UPDATE TIME
+pods           29-06-2024 19:43:19  29-06-2024 19:43:19
+test           29-06-2024 19:27:04  29-06-2024 19:27:04
+pvcs           29-06-2024 12:33:02  29-06-2024 12:33:02
+strimzi-kafka  29-06-2024 12:33:02  29-06-2024 12:33:02
+```
+
+> [Example dashboard | pods.yml](../examples/commands/pods-wide.yml)
+
+
+```bash
+kptop --dashboard pods
+```
+
+![alt text](./images/dashboard-pods.png)
+
+<br>
+
+> [Example dashboard | pods.yml](../examples/commands/pods-wide.yml)
+
+```bash
+kptop --dashboard pvcs
+```
+
+![alt text](./images/dashboard-pvcs.png)
+
+
+<br>
+
+
+```bash
+kptop --list-commands
+```
+
+```
+COMMAND    CREATION TIME        UPDATE TIME
+pods       29-06-2024 12:33:02  29-06-2024 12:33:02
+pvcs       29-06-2024 12:33:02  29-06-2024 12:33:02
+pods-wide  29-06-2024 12:33:02  29-06-2024 12:33:02
+```
+
+
+> [Example command | pods-wide.yml](../examples/commands/pods-wide.yml)
+
+```bash
+kptop --command pods-wide -n kafka
+```
+
+```
+NAME                                               MEMORY REQUESTS    MEMORY LIMITS    CPU REQUESTS    CPU LIMITS    NODE                                       ARCH    INSTANCE TYPE    AWS AZ      CAPACITY TYPE
+kafka-test-entity-operator-798859b74d-5jh58        1.0 gb             2.0 gb           0.4             2.0           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-cp-schema-registry-546f5f8b5d-2j48f     6.0 gb             8.0 gb           0.5             1.0           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-cruise-control-5c4cf6749-ss7l2          512.0 mb           2.0 gb           1.0             2.0           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-strimzi-canary-8686978cb7-dbrf4         64.0 mb            64.0 mb          0.1             0.1           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-brokers-az-c-300                        5.0 gb             8.0 gb           1.0             2.0           ip-0-0-184-231.eu-west-1.compute.internal  arm64   m7g.large        eu-west-1c  on-demand
+kafka-test-brokers-az-a-100                        5.0 gb             8.0 gb           1.0             2.0           ip-0-0-60-93.eu-west-1.compute.internal    arm64   m7g.large        eu-west-1a  on-demand
+kafka-test-cp-schema-registry-546f5f8b5d-486b9     6.0 gb             8.0 gb           0.5             1.0           ip-0-0-30-147.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-testing-kafka-k8s-exporter-6fb7c6dqknnl 512.0 mb           1.0 gb           0.1             0.3           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-kafka-exporter-c58966cd6-r2tsj          256.0 mb           512.0 mb         0.1             0.5           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-kafdrop-67ff5d5b4-77khq                 256.0 mb           1.0 gb           0.2             0.5           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-brokers-az-b-200                        5.0 gb             8.0 gb           1.0             2.0           ip-0-0-100-105.eu-west-1.compute.internal  arm64   m7g.large        eu-west-1b  on-demand
+kafka-test-kafka-ui-55fcf964d7-n5j7r               256.0 mb           1.0 gb           0.2             0.5           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-zookeeper-0                             2.0 gb             4.0 gb           1.0             2.0           ip-0-0-30-147.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-zookeeper-2                             2.0 gb             4.0 gb           1.0             2.0           ip-0-0-155-163.eu-west-1.compute.internal  amd64   m5.xlarge        eu-west-1c  on-demand
+kafka-test-cp-schema-registry-546f5f8b5d-pwlzk     6.0 gb             8.0 gb           0.5             1.0           ip-0-0-155-163.eu-west-1.compute.internal  amd64   m5.xlarge        eu-west-1c  on-demand
+burrow-release-kafka-burrow-79c657bfff-q4lx7       128.0 mb           256.0 mb         0.1             0.1           ip-0-0-30-147.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-zookeeper-1                             2.0 gb             4.0 gb           1.0             2.0           ip-0-0-71-148.eu-west-1.compute.internal   amd64   c5.large         eu-west-1b  on-demand
+kafka-test-cruise-control-ui-569ccc5897-8jqdq      ?                  ?                ?               ?             ip-0-0-33-177.eu-west-1.compute.internal   amd64   c5.large         eu-west-1a  on-demand
+kafka-test-cruise-control-ui-569ccc5897-zl987      ?                  ?                ?               ?             ip-0-0-33-177.eu-west-1.compute.internal   amd64   c5.large         eu-west-1a  on-demand
+```
+
+<br>
+
+---
+
+Logging
+
+Default log file location is "`/tmp/kptop.log`"
+
+
+<br>
diff --git a/docs/installation.md b/docs/installation.md
new file mode 100644
index 0000000..92e31d8
--- /dev/null
+++ b/docs/installation.md
@@ -0,0 +1,43 @@
+---
+layout: default
+nav_order: 1
+# permalink: /
+# parent: Home
+permalink: /installation
+title: Installation
+markdown: Kramdown
+has_children: false
+kramdown:
+  parse_block_html: true
+  auto_ids: true
+  syntax_highlighter: coderay
+---
+
+<button class="btn js-toggle-dark-mode">Switch to Dark Mode
+
+<script>
+const toggleDarkMode = document.querySelector('.js-toggle-dark-mode');
+
+jtd.addEvent(toggleDarkMode, 'click', function(){
+  if (jtd.getTheme() === 'dark') {
+    jtd.setTheme('light');
+    toggleDarkMode.textContent = 'Switch to Dark Mode';
+  } else {
+    jtd.setTheme('dark');
+    toggleDarkMode.textContent = 'Switch to Light Mode';
+  }
+});
+</script>
+
+# Install KPtop
+{: .fs-9 }
+
+<br>
+
+> Compatible with Python 3.6+
+
+[on PyPi](https://pypi.org/project/kptop)
+
+```bash
+pip3 install kptop --upgrade
+```
diff --git a/docs3/README.md b/docs3/README.md
new file mode 100644
index 0000000..667a007
--- /dev/null
+++ b/docs3/README.md
@@ -0,0 +1,243 @@
+
+# Kube-Prometheus-Top [ kptop ]
+
+A Python tool that offers beautiful CLI monitoring based on Prometheus metrics, with Kubernetes integration through PodPortForward
+
+Allowing you to create your own custom CLI dashboards & CLI commands with custom layouts, variables, CLI arguments !
+
+<br>
+
+# Motivation
+Prometheus is widely used with different kinds of metrics - Let's make CLI monitoring more powerful with Prometheus data.
+
+
+<br>
+
+---
+
+
+# Installation
+
+> Compatible with Python 3.6+
+
+[on PyPi](https://pypi.org/project/kptop)
+
+```bash
+pip3 install kptop --upgrade
+```
+
+<br>
+
+---
+
+
+## Environment Variables
+<a id=env></a>
+
+| ENV | Description                                                                          | Default | Required |
+| ----- | -------------------------------------------------------------------------------------- | --------- | ---------- |
+| `KPTOP_CONNECTION_METHOD`    | The way to connect to Prometheus server<br />**options:** ['prometheus_endpoint', 'pod_portForward'] | <br />      | Yes      |
+
+There are 2 options to connect KPtop to Prometheus:
+1. With a Prometheus server endpoint
+    - Suitable if Prometheus is exposed (with an ingress for example)
+2. With 'K8s pod port-forward' (Through K8s API-Server)
+    - Suitable if Prometheus is Not exposed (Only rechable with K8s cluster access)
+
+
+#### `prometheus_endpoint` ENVs
+
+| ENV | Description                                                     | Default | Required |
+| ----- | ----------------------------------------------------------------- | --------- | ---------- |
+| `KPTOP_PROMETHEUS_SERVER`    | Prometheus server URL                                           |         | Yes      |
+| `KPTOP_BASIC_AUTH_ENABLED`    | Whether basic authentication is needed to connect to Prometheus | False   | No       |
+| `KPTOP_PROMETHEUS_USERNAME`    | Prometheus username                                             |         | No       |
+| `KPTOP_PROMETHEUS_PASSWORD`    | Prometheus password                                             |         | No       |
+| `KPTOP_INSECURE`    | Verify SSL certificate                                          | False   | No       |
+
+
+<br>
+
+#### `pod_portForward` ENVs
+
+| ENV | Description                                            | Default | Required |
+| ----- | -------------------------------------------------------- | --------- | ---------- |
+| `KPTOP_PROMETHEUS_POD_NAME`    | Prometheus pod name                                    |         | Yes      |
+| `KPTOP_PROMETHEUS_POD_PORT`    | Prometheus port number                                 | 9090    | No       |
+| `KPTOP_PROMETHEUS_POD_NAMESPACE`    | The name space in which the Prometheus pod is deployed | default | No       |
+| `KUBECONFIG`    | custom K8s kube config file                            | *default path*        | No       |
+
+
+<br>
+
+#### General ENVs
+
+| ENV                                  | Description                                                  | Default               | Required |
+| ------------------------------------ | ------------------------------------------------------------ | --------------------- | -------- |
+| `KPTOP_START_GRAPHS_WITH_ZERO`       | By default graphs begin with '0'  to let the graph take its full hight | True                  | NO       |
+| `KPTOP_LOGGING_DIR`                  | Choose a different logging directory                         | /tmp/                 | NO       |
+| `KPTOP_GRAPH_WIDTH`                  | Choose a custom graphs width                                 | 45                    | NO       |
+| `KPTOP_DEFAULT_DASHBOARDS_DIRECTORY` | Default directory contains the dashboards yaml files         | /var/kptop/dashboards | NO       |
+| `KPTOP_DEFAULT_COMMANDS_DIRECTORY`   | Default directory contains the commands yaml files           | /var/kptop/commands   | NO       |
+
+
+
+<br>
+
+---
+
+# CLI Arguments
+<a id=cli></a>
+
+
+| ENV                         | Description                                                  |
+| --------------------------- | ------------------------------------------------------------ |
+| `--dashboard` , `-D`        | Specify a dashboard YAML file                                |
+| `--command` , `-C`          | Specify a command YAML file                                  |
+| `--list-dashboards` , `-ld` | List all the available dashboards                            |
+| `--list-commands` , `-lc`   | List all the available commands                              |
+| `--debug`,  `-d`            | Enable debugging logging mode                                |
+| `--version`,  `-V`          | Show kptop version                                           |
+| `--print-layout`,  `-pl`    | Print the dashboard empty layout                             |
+| `--vhelp` ,  `-vh`          | Print the arguments including "the variables arguments defined in your command yaml file" |
+
+
+<br>
+
+---
+
+
+# Usage
+
+
+## [1] Add the Prometheus connection Environment Variables
+
+## Example
+
+<br>
+
+Add the ENVs and you're good to go.
+
+_*Examples*_
+
+```bash
+export KPTOP_CONNECTION_METHOD="pod_portForward"
+export KPTOP_PROMETHEUS_POD_NAME="my-prometheus-server-0"
+export KPTOP_PROMETHEUS_POD_PORT="9090"
+export KPTOP_PROMETHEUS_POD_NAMESPACE="monitoring"
+```
+
+> Or
+
+```bash
+export KPTOP_CONNECTION_METHOD="prometheus_endpoint"
+export KPTOP_PROMETHEUS_SERVER="http://prometheus.home-lab.com"
+```
+
+
+<br>
+
+## [2] Configure the location of your dashboards & commands
+
+
+Example:
+
+```bash
+export KPTOP_DEFAULT_DASHBOARDS_DIRECTORY="/Users/YOU/kptop/examples/dashboards"
+export KPTOP_DEFAULT_COMMANDS_DIRECTORY="/Users/YOU/kptop/examples/dashboards"
+```
+
+
+
+## Run dashboards / commands !
+
+### [Dashboards Doc](./dashboards/)
+### [Commands Doc](./commands/)
+
+
+```bash
+kptop --list-dashboards
+```
+
+```
+DASHBOARD      CREATION TIME        UPDATE TIME
+pods           29-06-2024 19:43:19  29-06-2024 19:43:19
+test           29-06-2024 19:27:04  29-06-2024 19:27:04
+pvcs           29-06-2024 12:33:02  29-06-2024 12:33:02
+strimzi-kafka  29-06-2024 12:33:02  29-06-2024 12:33:02
+```
+
+> [Example dashboard | pods.yml](../examples/commands/pods-wide.yml)
+
+
+```bash
+kptop --dashboard pods
+```
+
+![alt text](./images/dashboard-pods.png)
+
+<br>
+
+> [Example dashboard | pods.yml](../examples/commands/pods-wide.yml)
+
+```bash
+kptop --dashboard pvcs
+```
+
+![alt text](./images/dashboard-pvcs.png)
+
+
+<br>
+
+
+```bash
+kptop --list-commands
+```
+
+```
+COMMAND    CREATION TIME        UPDATE TIME
+pods       29-06-2024 12:33:02  29-06-2024 12:33:02
+pvcs       29-06-2024 12:33:02  29-06-2024 12:33:02
+pods-wide  29-06-2024 12:33:02  29-06-2024 12:33:02
+```
+
+
+> [Example command | pods-wide.yml](../examples/commands/pods-wide.yml)
+
+```bash
+kptop --command pods-wide -n kafka
+```
+
+```
+NAME                                               MEMORY REQUESTS    MEMORY LIMITS    CPU REQUESTS    CPU LIMITS    NODE                                       ARCH    INSTANCE TYPE    AWS AZ      CAPACITY TYPE
+kafka-test-entity-operator-798859b74d-5jh58        1.0 gb             2.0 gb           0.4             2.0           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-cp-schema-registry-546f5f8b5d-2j48f     6.0 gb             8.0 gb           0.5             1.0           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-cruise-control-5c4cf6749-ss7l2          512.0 mb           2.0 gb           1.0             2.0           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-strimzi-canary-8686978cb7-dbrf4         64.0 mb            64.0 mb          0.1             0.1           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-brokers-az-c-300                        5.0 gb             8.0 gb           1.0             2.0           ip-0-0-184-231.eu-west-1.compute.internal  arm64   m7g.large        eu-west-1c  on-demand
+kafka-test-brokers-az-a-100                        5.0 gb             8.0 gb           1.0             2.0           ip-0-0-60-93.eu-west-1.compute.internal    arm64   m7g.large        eu-west-1a  on-demand
+kafka-test-cp-schema-registry-546f5f8b5d-486b9     6.0 gb             8.0 gb           0.5             1.0           ip-0-0-30-147.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-testing-kafka-k8s-exporter-6fb7c6dqknnl 512.0 mb           1.0 gb           0.1             0.3           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-kafka-exporter-c58966cd6-r2tsj          256.0 mb           512.0 mb         0.1             0.5           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-kafdrop-67ff5d5b4-77khq                 256.0 mb           1.0 gb           0.2             0.5           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-brokers-az-b-200                        5.0 gb             8.0 gb           1.0             2.0           ip-0-0-100-105.eu-west-1.compute.internal  arm64   m7g.large        eu-west-1b  on-demand
+kafka-test-kafka-ui-55fcf964d7-n5j7r               256.0 mb           1.0 gb           0.2             0.5           ip-0-0-16-205.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-zookeeper-0                             2.0 gb             4.0 gb           1.0             2.0           ip-0-0-30-147.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-zookeeper-2                             2.0 gb             4.0 gb           1.0             2.0           ip-0-0-155-163.eu-west-1.compute.internal  amd64   m5.xlarge        eu-west-1c  on-demand
+kafka-test-cp-schema-registry-546f5f8b5d-pwlzk     6.0 gb             8.0 gb           0.5             1.0           ip-0-0-155-163.eu-west-1.compute.internal  amd64   m5.xlarge        eu-west-1c  on-demand
+burrow-release-kafka-burrow-79c657bfff-q4lx7       128.0 mb           256.0 mb         0.1             0.1           ip-0-0-30-147.eu-west-1.compute.internal   amd64   m5.xlarge        eu-west-1a  on-demand
+kafka-test-zookeeper-1                             2.0 gb             4.0 gb           1.0             2.0           ip-0-0-71-148.eu-west-1.compute.internal   amd64   c5.large         eu-west-1b  on-demand
+kafka-test-cruise-control-ui-569ccc5897-8jqdq      ?                  ?                ?               ?             ip-0-0-33-177.eu-west-1.compute.internal   amd64   c5.large         eu-west-1a  on-demand
+kafka-test-cruise-control-ui-569ccc5897-zl987      ?                  ?                ?               ?             ip-0-0-33-177.eu-west-1.compute.internal   amd64   c5.large         eu-west-1a  on-demand
+```
+
+<br>
+
+---
+
+Logging
+
+Default log file location is "`/tmp/kptop.log`"
+
+
+<br>
diff --git a/docs3/commands/README.md b/docs3/commands/README.md
new file mode 100644
index 0000000..e86397d
--- /dev/null
+++ b/docs3/commands/README.md
@@ -0,0 +1,91 @@
+
+# KPtop Custom Commands
+
+Create monitoring command lines easily with a simple yaml file !
+
+
+
+## Examples
+- [pods.yml](../../examples/commands/pods.yml)
+- [pods-wide.yml](../../examples/commands/pods-wide.yml)
+- [pvcs.yml](../../examples/commands/pvcs.yml)
+
+
+<br>
+
+---
+
+<br>
+
+## Command YAMl structure
+
+
+### variables
+
+Take a list of variables, and optionally you can set a CLi argument for a variable
+
+|               | type | description                                          | default | required |
+| --------------- | ------ | ------------------------------------------------------ | --------- | ---------- |
+| name          | `String`     | variable name ,, also used for the CLI argument name |         | True     |
+| default<br />     | `String`     | devault value for the variable                       |         | <br />       |
+| cliArgument<br /> | `Dict`     | CLI argument options for the variable                | <br />      |          |
+
+
+### cliArgument
+
+|            | type | description                                        | default | required |
+| ------------ | ------ | ---------------------------------------------------- | --------- | ---------- |
+| enable     | `Boolean`     | Enable CLI argument for the variable               |         | True     |
+| short<br />    | `String`     | short for the argument                             |         | True     |
+| required<br /> | `Boolean`     | Wether the argument is required to run the command | False   | False    |
+
+
+### execute (dict)
+
+|                      | type | description                                                                      | default                                                         | required | options |
+| ---------------------- | ------ | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ---------- | --------- |
+| type                 | `String`     | Data type to display on the terminal                                             |                                                                 | True     | `advancedTable`        |
+| advancedTableColumns | `List`     | List of coulmns for the table, each column has its own metric                    |                                                                 | True     |         |
+| custom_key           | `String`     | specify a custom key for metric result, You can compensate labels with "`{{LABEL}}`" syntax | default labels result (string composed of summed labels .. ex. `sum(metric) by (pod, namespace)` |          |         |
+| advancedTableOptions | `Dict`     | options to control how the resulted table looks                                  |                                                                 |          |         |
+
+
+### advancedTableColumns
+
+|                      | type | description                                                                                                                                   | default | required | options        |
+| ---------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------- | ---------------- |
+| COULMN NAME <br />EX: `- memory usage:`<br /> | `String`     | <br />                                                                                                                                            |         | <br />       | <br />             |
+| metric               | `String`<br />   | Prometheus metric to qurey                                                                                                                    |         | <br />       |                |
+| metricUnit<br />         | `String`<br />   | metric result value unit                                                                                                                      | byte    |          | `None`, `kb`, `byte`, `mb`, `gb`, `tb`, `seconds`, `percentage` |
+| autoConvertValue<br />   | `Boolean`<br />   | Auto convert the metric value based on the metricUnit .. for example, if metric value is in byte, it would be converted to kb, mb, gb .. etc. | False   | False    |                |
+
+
+### advancedTableOptions
+
+|                    | type | description                                    | default | required | options |
+| -------------------- | ------ | ------------------------------------------------ | --------- | ---------- | --------- |
+| tableType          | `String`     | the type of table, defines how the table looks | plain   | False    | [All the types supported here](https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format) 🙂<br />   |
+| headersUppercase<br /> | `Boolean`     | <br />                                             | True    | False    |         |
+| showTableIndex<br />   | `Boolean`<br />   | how table idex on the left                     | False   | False    |         |
+
+
+<br>
+
+---
+
+<br>
+
+
+## List commands
+
+```bash
+kptop --list-commands
+```
+
+
+## Run command
+
+
+```bash
+kptop --command <COMMAND-NAME>
+```
diff --git a/docs3/dashboards/README.md b/docs3/dashboards/README.md
new file mode 100644
index 0000000..1435582
--- /dev/null
+++ b/docs3/dashboards/README.md
@@ -0,0 +1,42 @@
+
+# KPtop Custom Commands
+
+Create monitoring dasboards on the terminal easily with a simple yaml file !
+
+
+
+## Examples
+- [pods.yml](../../examples/dashboards/pods.yml)
+- [pvcs.yml](../../examples/dashboards/pvcs.yml)
+
+
+<br>
+
+---
+
+<br>
+
+## Command YAMl structure
+
+To be added.
+
+
+<br>
+
+---
+
+<br>
+
+## List dashboards
+
+```bash
+kptop --list-dashboards
+```
+
+
+## Run dashboard
+
+
+```bash
+kptop --dashboard <DASHBOARD-NAME>
+```
diff --git a/docs3/images/dashboard-pods.png b/docs3/images/dashboard-pods.png
new file mode 100644
index 0000000..697f941
Binary files /dev/null and b/docs3/images/dashboard-pods.png differ
diff --git a/docs3/images/dashboard-pvcs.png b/docs3/images/dashboard-pvcs.png
new file mode 100644
index 0000000..674899c
Binary files /dev/null and b/docs3/images/dashboard-pvcs.png differ
diff --git a/docs/port-forward.md b/docs3/to.delete/port-forward.md
similarity index 100%
rename from docs/port-forward.md
rename to docs3/to.delete/port-forward.md
diff --git a/examples/commands/pods-wide.yml b/examples/commands/pods-wide.yml
new file mode 100644
index 0000000..c661243
--- /dev/null
+++ b/examples/commands/pods-wide.yml
@@ -0,0 +1,71 @@
+command:
+  name: Pods more Info
+  description: Kubernetes Pods info of a specific namespace
+
+  variables:
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+    - name: namespace
+      default: default
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+
+  execute:
+    type: advancedTable
+    advancedTableColumns:
+      - memory requests:
+        metric: |
+          sum(kube_pod_container_resource_requests{resource="memory", unit="byte", namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod)
+        metricUnit: byte
+        autoConvertValue: true
+      - memory limits:
+        metric: |
+          sum(kube_pod_container_resource_limits{resource="memory", unit="byte", namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod)
+        metricUnit: byte
+      - cpu requests:
+        metric: |
+          sum(kube_pod_container_resource_requests{resource="cpu", unit="core", namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod)
+        metricUnit: None
+      - cpu limits:
+        metric: |
+          sum(kube_pod_container_resource_limits{resource="cpu", unit="core", namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod)
+        metricUnit: None
+      - node:
+        metric: |
+          sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone, instance, kubernetes_io_arch, node_kubernetes_io_instance_type, topology_kubernetes_io_zone, karpenter_sh_capacity_type)
+        metricUnit: byte
+        valueFromLabel: instance
+      - arch:
+        metric: |
+          sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone, instance, kubernetes_io_arch, node_kubernetes_io_instance_type, topology_kubernetes_io_zone, karpenter_sh_capacity_type)
+        metricUnit: byte
+        valueFromLabel: kubernetes_io_arch
+      - instance type:
+        metric: |
+          sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone, instance, kubernetes_io_arch, node_kubernetes_io_instance_type, topology_kubernetes_io_zone, karpenter_sh_capacity_type)
+        metricUnit: byte
+        valueFromLabel: node_kubernetes_io_instance_type
+      - aws az:
+        metric: |
+          sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone, instance, kubernetes_io_arch, node_kubernetes_io_instance_type, topology_kubernetes_io_zone, karpenter_sh_capacity_type)
+        metricUnit: byte
+        valueFromLabel: topology_kubernetes_io_zone
+      - capacity type:
+        metric: |
+          sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone, instance, kubernetes_io_arch, node_kubernetes_io_instance_type, topology_kubernetes_io_zone, karpenter_sh_capacity_type)
+        metricUnit: byte
+        valueFromLabel: karpenter_sh_capacity_type
+
+    custom_key: "{{pod}}"
+    advancedTableOptions:
+      tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+      headersUppercase: true
+      autoConvertValue: true
+      showTableIndex: false
+      updateIntervalSeconds: 3
diff --git a/examples/commands/pods.yml b/examples/commands/pods.yml
new file mode 100644
index 0000000..b6d4034
--- /dev/null
+++ b/examples/commands/pods.yml
@@ -0,0 +1,70 @@
+command:
+  name: Pods Info
+  description: Kubernetes Pods info of a specific namespace
+
+  variables:
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+    - name: namespace
+      default: default
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+
+  execute:
+    type: advancedTable
+    advancedTableColumns:
+      - memory usage:
+        metric: |
+          sort_desc(sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory usage %:
+        metric: |
+          sort_desc(
+            (
+              sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone)
+              /
+              sum(container_spec_memory_limit_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone)
+            ) * 100
+          )
+        metricUnit: percentage
+      - memory limit:
+        metric: |
+          sort_desc(sum(container_spec_memory_limit_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory cache:
+        metric: |
+          sort_desc(sum(container_memory_cache{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory swap:
+        metric: |
+          sum(container_memory_swap{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone)
+        metricUnit: byte
+      - memory kernel usage:
+        metric: |
+          sum(container_memory_kernel_usage{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone)
+        metricUnit: byte
+      - memory max usage:
+        metric: |
+          sum(container_memory_max_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone)
+        metricUnit: byte
+      - CPU Usage %:
+        metric: |
+          100 * sum(rate(container_cpu_usage_seconds_total{image!="", container!="POD", namespace=~"$namespace", pod=~"$pod", pod!=""}[5m])) by (pod, namespace) /
+          sum(kube_pod_container_resource_limits{namespace=~"$namespace", pod=~"$pod", container!="POD", pod!=""}) by (pod, namespace)
+        metricUnit: percentage
+      - up time:
+        metric: |
+          sum(time() - kube_pod_start_time{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod)
+        metricUnit: seconds
+    custom_key: "{{pod}}" # "{{pod}} - {{topology_ebs_csi_aws_com_zone}}"
+    advancedTableOptions:
+      tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+      headersUppercase: true
+      autoConvertValue: true
+      showTableIndex: false
diff --git a/examples/commands/pvcs.yml b/examples/commands/pvcs.yml
new file mode 100644
index 0000000..a0859e9
--- /dev/null
+++ b/examples/commands/pvcs.yml
@@ -0,0 +1,66 @@
+command:
+  name: Pods Info
+  description: Kubernetes Pods info of a specific namespace
+
+  variables:
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+    - name: namespace
+      default: default
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+
+  execute:
+    type: advancedTable
+    advancedTableColumns:
+      - memory usage:
+        metric: |
+          sort_desc(sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory usage %:
+        metric: |
+          sort_desc(
+            (
+              sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+              /
+              sum(container_spec_memory_limit_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+            ) * 100
+          )
+        metricUnit: percentage
+      - memory limit:
+        metric: |
+          sort_desc(sum(container_spec_memory_limit_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory cache:
+        metric: |
+          sort_desc(sum(container_memory_cache{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory swap:
+        metric: |
+          sum(container_memory_swap{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+        metricUnit: byte
+      - memory max usage:
+        metric: |
+          sum(container_memory_max_usage_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+        metricUnit: byte
+      - file descriptors:
+        metric: |
+          sort_desc(sum(container_file_descriptors{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: None
+      - up time:
+        metric: |
+          sum(time() - kube_pod_start_time{namespace=~"$namespace", pod=~"$pod"}) by (pod)
+        metricUnit: seconds
+    custom_key: "{{pod}}" # "{{pod}} - {{topology_ebs_csi_aws_com_zone}}"
+    advancedTableOptions:
+      tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+      headersUppercase: true
+      autoConvertValue: true
+      showTableIndex: false
+      updateIntervalSeconds: 3
diff --git a/examples/dashboards/pods.yml b/examples/dashboards/pods.yml
new file mode 100644
index 0000000..5c6bad5
--- /dev/null
+++ b/examples/dashboards/pods.yml
@@ -0,0 +1,158 @@
+dashboard:
+  name: Kafka pods
+  description: Kafka Pods resources usage overview
+  layout:
+    splitMode: row # row
+    fullScreen: true
+    header:
+      enable: false
+      size: 3
+      ratio: 1
+    body:
+      boxes:
+        left:
+          enable: true
+          size: 190
+          ratio: 1
+          split_mode: column
+          split:
+            left_a:
+              size: 0
+              ratio: 1
+        middle:
+          enable: false
+          size: 0
+          ratio: 1
+          split_mode: column
+          split:
+            middle_a:
+              size: 0
+              ratio: 1
+            middle_b:
+              size: 0
+              ratio: 1
+            middle_c:
+              size: 0
+              ratio: 1
+        right:
+          enable: true
+          size: 0
+          ratio: 1
+          split_mode: column
+          split:
+            right_a:
+              size: 0
+              ratio: 1
+            right_b:
+              size: 0
+              ratio: 1
+
+  variables:
+    - name: namespace
+      default: .*
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+
+  visualization:
+    - name: Pods Memory Usage
+      enable: true
+      box: right_a
+      type: asciiGraph # || progressBarList || asciiText
+      metricUnit: mb
+      # Sorting is important if you expect lots of results
+      metric: >
+        sort_desc(sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod) / 1024 / 1024)
+      custom_key: "🥕 {{pod}}"
+      asciiGraphOptions:
+        height: 0
+        width: 80
+        maxHeight: 17
+        maxWidth: 45
+        updateIntervalSeconds: 2
+
+    - name: Kafka pods memory usage (Sorted by higher memory usage)
+      enable: true
+      box: right_b
+      type: progressBarList
+      metricUnit: mb
+      metrics:
+        total_value_metric: |
+          # Memory limits
+          sum(container_spec_memory_limit_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod)
+        usage_value_metric: |
+          # memory usage sorted by higher usage
+          sort_desc(sum(container_memory_usage_bytes{namespace=~".*", pod=~".*", pod!=""}) by (pod))
+      custom_key: "{{pod}}"
+      progressBarListOptions:
+        maxItemsCount: 50
+        lineBreak: true
+        showBarPercentage: true
+        barWidth: 25
+        updateIntervalSeconds: 5
+
+    - name: Kafka pods details (advancedTable example)
+      enable: true
+      box: left_a
+      type: advancedTable
+      advancedTableColumns:
+        - memory usage:
+          metric: |
+            sort_desc(sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+          autoConvertValue: true
+        - memory usage %:
+          metric: |
+            sort_desc(
+              (
+                sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone)
+                /
+                sum(container_spec_memory_limit_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone)
+              ) * 100
+            )
+          metricUnit: percentage
+          autoConvertValue: true
+        - memory limit:
+          metric: |
+            sort_desc(sum(container_spec_memory_limit_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+          autoConvertValue: true
+        - memory cache:
+          metric: |
+            sort_desc(sum(container_memory_cache{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+          autoConvertValue: true
+        - memory swap:
+          metric: |
+            sum(container_memory_swap{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone)
+          metricUnit: byte
+          autoConvertValue: true
+        # - file descriptors:
+        #   metric: |
+        #     sort_desc(sum(container_file_descriptors{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        #   metricUnit: None
+        - CPU Usage Percentage:
+          metric: |
+            100 * sum(irate(container_cpu_usage_seconds_total{image!="", container!="POD", namespace=~"$namespace", pod!=""}[5m])) by (pod, namespace) /
+            sum(kube_pod_container_resource_limits{namespace=~"$namespace", container!="POD", pod!=""}) by (pod, namespace)
+          metricUnit: percentage
+          autoConvertValue: true
+        - AWS AZ:
+          metric: |
+            sort_desc(sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod", pod!=""}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+          autoConvertValue: true
+          valueFromLabel: topology_ebs_csi_aws_com_zone
+      custom_key: "{{pod}}"
+      advancedTableOptions:
+        tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+        headersUppercase: true
+        showTableIndex: true
+        updateIntervalSeconds: 3
diff --git a/examples/dashboards/pvcs.yml b/examples/dashboards/pvcs.yml
new file mode 100644
index 0000000..39f255d
--- /dev/null
+++ b/examples/dashboards/pvcs.yml
@@ -0,0 +1,127 @@
+dashboard:
+  name: Kafka cluster
+  description: Staging Kafka dashboard
+  layout:
+    splitMode: column # row
+    fullScreen: true
+    header:
+      enable: false
+      size: 3
+      ratio: 1
+    body:
+      boxes:
+        left:
+          enable: true
+          size: 0
+          ratio: 1
+          split_mode: column
+          split:
+            left_a:
+              size: 0
+              ratio: 1
+            left_b:
+              size: 0
+              ratio: 1
+        middle: {}
+        right: {}
+
+  variables:
+    - name: namespace
+      default: .*
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+    - name: pvc
+      default: .*
+      cliArgument:
+        enable: true
+        short: -pv
+        required: false
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+
+  visualization:
+    - name: Persistent Volumes Usage [Sorted] (asciiGraph example)
+      box: left_a
+      enable: true
+      type: asciiGraph
+      metricUnit: mb
+      metric: |
+        sort_desc(
+          sum(kubelet_volume_stats_used_bytes{namespace=~"$namespace", persistentvolumeclaim=~"$pvc"}) by (namespace, persistentvolumeclaim) / 1024 / 1024
+        )
+      custom_key: "🍅 {{persistentvolumeclaim}}"
+      asciiGraphOptions:
+        height: 0
+        width: 200
+        maxHeight: 17
+        maxWidth: 45
+        updateIntervalSeconds: 2
+      historyData:
+        enable: true
+        time: 5m
+
+    - name: Persistent Volumes Usage (advancedTable example)
+      enable: true
+      box: left_b
+      type: advancedTable
+      advancedTableColumns:
+        - disk capacity:
+          metric: |
+            sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim=~"$pvc", namespace=~"$namespace"}) by (persistentvolumeclaim, namespace, topology_kubernetes_io_zone, kubernetes_io_hostname,  node_kubernetes_io_instance_type)
+          metricUnit: byte
+        - disk used:
+          metric: |
+            sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim=~"$pvc", namespace=~"$namespace"}) by (persistentvolumeclaim, namespace, topology_kubernetes_io_zone, kubernetes_io_hostname,  node_kubernetes_io_instance_type)
+          metricUnit: byte
+        - disk used %:
+          metric: |
+            (sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim=~"$pvc", namespace=~"$namespace"}) by (persistentvolumeclaim, namespace, topology_kubernetes_io_zone, kubernetes_io_hostname, node_kubernetes_io_instance_type) /
+             sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim=~"$pvc", namespace=~"$namespace"}) by (persistentvolumeclaim, namespace, topology_kubernetes_io_zone, kubernetes_io_hostname, node_kubernetes_io_instance_type)) * 100
+          metricUnit: percentage
+        - disk available:
+          metric: |
+            sum(kubelet_volume_stats_available_bytes{persistentvolumeclaim=~"$pvc", namespace=~"$namespace"}) by (persistentvolumeclaim, namespace, topology_kubernetes_io_zone, kubernetes_io_hostname,  node_kubernetes_io_instance_type)
+          metricUnit: byte
+        - namespace:
+          metric: |
+            sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim=~"$pvc", namespace=~"$namespace"}) by (persistentvolumeclaim, namespace, topology_kubernetes_io_zone, kubernetes_io_hostname,  node_kubernetes_io_instance_type)
+          metricUnit: byte
+          valueFromLabel: namespace
+        - pod:
+          metric: |
+            sum(kube_pod_spec_volumes_persistentvolumeclaims_info{persistentvolumeclaim=~"$pvc", namespace=~"$namespace", pod=~"$pod"}) by (pod, persistentvolumeclaim, volume)
+          metricUnit: byte
+          valueFromLabel: pod
+        # - node:
+        #   metric: |
+        #     sum(kubelet_volume_stats_capacity_bytes) by (persistentvolumeclaim, namespace, topology_kubernetes_io_zone, kubernetes_io_hostname,  node_kubernetes_io_instance_type)
+        #   metricUnit: byte
+        #   valueFromLabel: kubernetes_io_hostname
+        - instance type:
+          metric: |
+            sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim=~"$pvc", namespace=~"$namespace"}) by (persistentvolumeclaim, namespace, topology_kubernetes_io_zone, kubernetes_io_hostname,  node_kubernetes_io_instance_type)
+          metricUnit: byte
+          valueFromLabel: node_kubernetes_io_instance_type
+        - AWS Zone:
+          metric: |
+            sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim=~"$pvc", namespace=~"$namespace"}) by (persistentvolumeclaim, namespace, topology_kubernetes_io_zone, kubernetes_io_hostname,  node_kubernetes_io_instance_type)
+          metricUnit: byte
+          valueFromLabel: topology_kubernetes_io_zone
+        - Inodes Usage %:
+          metric: |
+            sum((kubelet_volume_stats_inodes_used{namespace=~"$namespace", persistentvolumeclaim=~"$pvc"} / (kubelet_volume_stats_inodes_used{namespace=~"$namespace", persistentvolumeclaim=~"$pvc"} + kubelet_volume_stats_inodes_free{namespace=~"$namespace", persistentvolumeclaim=~"$pvc"})) * 100) by (namespace, persistentvolumeclaim)
+          metricUnit: percentage
+
+      custom_key: "💾 {{persistentvolumeclaim}}"
+      advancedTableOptions:
+        tableType: simple # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+        headersUppercase: true
+        autoConvertValue: true
+        showTableIndex: true
+        updateIntervalSeconds: 3
diff --git a/examples/dashboards/strimzi-kafka.yml b/examples/dashboards/strimzi-kafka.yml
new file mode 100644
index 0000000..35597c8
--- /dev/null
+++ b/examples/dashboards/strimzi-kafka.yml
@@ -0,0 +1,212 @@
+dashboard:
+  name: Kafka cluster
+  description: Staging Kafka dashboard
+  layout:
+    splitMode: row # row
+    fullScreen: true
+    header:
+      enable: false
+      size: 3
+      ratio: 1
+    body:
+      boxes:
+        left:
+          enable: true
+          size: 200
+          ratio: 1
+          split_mode: column
+          split:
+            left_a:
+              size: 0
+              ratio: 1
+            # left_b:
+            #   size: 25
+            #   ratio: 1
+            # left_c:
+            #   size: 0
+            #   ratio: 1
+            # left_d:
+            #   size: 0
+            #   ratio: 1
+        middle:
+          enable: false
+          size: 0
+          ratio: 1
+          split_mode: column
+          split:
+            middle_a:
+              size: 0
+              ratio: 1
+            middle_b:
+              size: 0
+              ratio: 1
+            middle_c:
+              size: 0
+              ratio: 1
+        right:
+          enable: true
+          size: 0
+          ratio: 1
+          split_mode: column
+          split:
+            right_a:
+              size: 0
+              ratio: 1
+            right_b:
+              size: 0
+              ratio: 1
+
+  # defaultDataSource:
+  #   type: prometheus
+  #   endpoint: ""
+  #   secure: false
+  #   basicAuthEnabled: false
+  #   basicAuthUserNameVariable: ""
+  #   basicAuthPasswordVariable: ""
+
+  variables:
+    - name: namespace
+      default: .*
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+    - name: kafka-topics-namespace
+      default: kafka-resources
+      cliArgument:
+        enable: true
+        short: -tn
+        required: false
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+
+  visualization:
+    - name: Kafka Data In per second.
+      box: right_a
+      enable: true
+      type: asciiGraph
+      metricUnit: kb # byte_to_kb_mb_gb_tb # dynamic_byte_convert
+      metric: >
+        sort_desc(sum(irate(kafka_server_brokertopicmetrics_bytesin_total{topic=~"$topic"}[5m])) by (strimzi_io_cluster, topic)) / 1024
+      custom_key: "🍅 {{topic}}"
+      asciiGraphOptions:
+        height: 0
+        width: 80
+        maxHeight: 17
+        maxWidth: 45
+        updateIntervalSeconds: 2
+      historyData:
+        enable: true
+        time: 5m
+
+    - name: Kafka Data Out per second.
+      enable: true
+      box: right_b
+      type: asciiGraph # || progressBarList || asciiText
+      metricUnit: kb
+      metric: >
+        sort_desc(sum(irate(kafka_server_brokertopicmetrics_bytesout_total{topic=~"$topic"}[5m])) by (strimzi_io_cluster, topic)) / 1024
+      custom_key: "🥕 {{topic}}"
+      asciiGraphOptions:
+        height: 0
+        width: 80
+        maxHeight: 17
+        maxWidth: 45
+        updateIntervalSeconds: 2
+        # historyData:
+        #   enable: true
+        #   time: 5m
+
+    # - name: Kafka pods memory usage (Sorted by higher memory usage)
+    #   enable: false
+    #   box: left_a
+    #   type: progressBarList
+    #   metricUnit: mb
+    #   metrics:
+    #     total_value_metric: |
+    #       # Memory limits
+    #       sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+    #     usage_value_metric: |
+    #       # memory usage sorted by higher usage
+    #       sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+    #   custom_key: "{{pod}}"
+    #   progressBarListOptions:
+    #     maxItemsCount: 10
+    #     lineBreak: true
+    #     showBarPercentage: true
+    #     barWidth: 25
+    #     updateIntervalSeconds: 5
+
+    # - name: Kafka Pods memory usage (simpleTable example)
+    #   enable: true
+    #   box: left_b
+    #   type: simpleTable
+    #   metricUnit: byte
+    #   metric: |
+    #     sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, namespace, karpenter_sh_capacity_type, topology_kubernetes_io_zone,node_kubernetes_io_instance_type)
+    #   # custom_key: |
+    #   #   f"{labels['pod']}"
+    #   simpleTableOptions:
+    #     tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+    #     showValue: true
+    #     headersUppercase: true
+    #     autoConvertValue: true
+    #     showTableIndex: true
+    #     updateIntervalSeconds: 5
+    - name: Kafka pods details (advancedTable example)
+      enable: true
+      box: left_a
+      type: advancedTable
+      advancedTableColumns:
+        - memory usage:
+          metric: |
+            sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+        - memory usage %:
+          metric: |
+            sort_desc(
+              (
+                sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+                /
+                sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+              ) * 100
+            )
+          metricUnit: percentage
+        - memory limit:
+          metric: |
+            sort_desc(sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+        - memory cache:
+          metric: |
+            sort_desc(sum(container_memory_cache{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+        - memory swap:
+          metric: |
+            sum(container_memory_swap{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+          metricUnit: byte
+          autoConvertValdue: true
+        # - file descriptors:
+        #   metric: |
+        #     sort_desc(sum(container_file_descriptors{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        #   metricUnit: None
+        - CPU Usage Percentage:
+          metric: |
+            100 * sum(rate(container_cpu_usage_seconds_total{image!="", container!="POD", namespace=~".*"}[5m])) by (pod, namespace) /
+            sum(kube_pod_container_resource_limits{namespace=~".*", container!="POD"}) by (pod, namespace)
+          metricUnit: percentage
+        - AWS AZ:
+          metric: |
+            sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+          valueFromLabel: topology_ebs_csi_aws_com_zone
+      custom_key: "{{pod}}" # "{{pod}} - {{topology_ebs_csi_aws_com_zone}}"
+      advancedTableOptions:
+        tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+        headersUppercase: true
+        autoConvertValue: true
+        showTableIndex: true
+        updateIntervalSeconds: 3
diff --git a/examples/dataSources/prometheus_http.yml b/examples/dataSources/prometheus_http.yml
new file mode 100644
index 0000000..5f0c7ed
--- /dev/null
+++ b/examples/dataSources/prometheus_http.yml
@@ -0,0 +1,21 @@
+dataSoures:
+  - name: staging prometheus
+    type: prometheus # || prometheusPodPortForward || KubernetesAPI
+    prometheusOptions:
+      prometheusEndpoint: http://..
+      basicAuthEnabled: false
+      basicAuthUsernameEnv: abc
+      basicAuthPasswordEnv: abc
+
+  - name: staging prometheus
+    type: prometheusPodPortForward
+    prometheusPodPortForwardOptions:
+      prometheusPodName: prometheus-0
+      prometheusPodNamespace: monitoring
+      kubeConfigFilePath: /Users/USER/.kube/config #~/.kube/config # default
+
+  - name: staging eks
+    type: KubernetesAPI # || prometheusPodPortForward || KubernetesAPI
+    KubernetesAPIOptions:
+      kubeConfigFilePath: /Users/USER/.kube/config #~/.kube/config # default
+      kubeProfile: abc
diff --git a/kptop_tool.py b/kptop_tool.py
index bd727ad..fcf19b6 100644
--- a/kptop_tool.py
+++ b/kptop_tool.py
@@ -1,20 +1,10 @@
-def run():
-    # It runs at the initilization
-    from kubePtop.cli import Cli
+from kubePtop.read_env import ReadEnv
+env = ReadEnv()
+env.read_env()
+from kubePtop.cli_args import Cli
+cli = Cli()
 
+def run():
+    cli.run()
 
 run()
-
-# from kubePtop.node_metrics import PrometheusNodeMetrics
-# from kubePtop.read_env import ReadEnv
-# env = ReadEnv()
-# env.read_env()
-# import rich
-
-# test = PrometheusNodeMetrics()
-# rich.print(test.nodeManagedK8sInfo('.*'))
-# print(test.topNode())
-# test.topNodeTable(option="cloud")
-# test.topNodeJson('ip-10-129-143-105.eu-west-1.compute.internal')
-
-
diff --git a/kubePtop/ascii_graph.py b/kubePtop/ascii_graph.py
index 0a55a1a..226cd47 100644
--- a/kubePtop/ascii_graph.py
+++ b/kubePtop/ascii_graph.py
@@ -6,8 +6,8 @@ class AsciiGraph:
     Create a Terminal Graph with 'asciichartpy'
     1. create a graph with 'create_graph()'
     2. update the graph with 'update_lst()'
-    
-    - the graph is write and upate to the '.graph' attribute (str)
+
+    - the graph is writen and upated to the '.graph' attribute (str)
     - the lines-names mapped colors are written to '.colors_description_str' attribute (str)
 
     # Example #
@@ -29,16 +29,260 @@ class AsciiGraph:
     exit(1)
     """
     def __init__(self):
-        self.colors = [asciichartpy.lightgreen, asciichartpy.lightblue, asciichartpy.lightyellow, asciichartpy.lightred, asciichartpy.lightcyan, asciichartpy.lightgray, asciichartpy.lightmagenta, asciichartpy.red, asciichartpy.green, asciichartpy.blue, asciichartpy.yellow, asciichartpy.cyan, asciichartpy.darkgray] # asciichartpy.black, asciichartpy.white
+
+        self.colors = [
+            '\033[38;5;2m',    # Green
+            '\033[38;5;1m',    # Maroon
+            '\033[38;5;3m',    # Olive
+            '\033[38;5;4m',    # Navy
+            '\033[38;5;5m',    # Purple
+            '\033[38;5;6m',    # Teal
+            '\033[38;5;12m',   # Blue
+            '\033[38;5;241m',  # Grey
+            '\033[38;5;7m',    # Silver
+            '\033[38;5;8m',    # Grey
+            '\033[38;5;9m',    # Red
+            '\033[38;5;10m',   # Lime
+            '\033[38;5;11m',   # Yellow
+            '\033[38;5;132m',  # HotPink3
+            '\033[38;5;133m',  # MediumOrchid3
+            '\033[38;5;134m',  # MediumOrchid
+            '\033[38;5;135m',  # MediumPurple2
+            '\033[38;5;136m',  # DarkGoldenrod
+            '\033[38;5;137m',  # LightSalmon3
+            '\033[38;5;138m',  # RosyBrown
+            '\033[38;5;139m',  # Grey63
+            '\033[38;5;140m',  # MediumPurple2
+            '\033[38;5;141m',  # MediumPurple1
+            '\033[38;5;13m',   # Fuchsia
+            '\033[38;5;14m',   # Aqua
+            # '\033[38;5;15m',   # White
+            '\033[38;5;16m',   # Grey0
+            '\033[38;5;17m',   # NavyBlue
+            '\033[38;5;18m',   # DarkBlue
+            '\033[38;5;19m',   # Blue3
+            '\033[38;5;20m',   # Blue3
+            '\033[38;5;21m',   # Blue1
+            '\033[38;5;22m',   # DarkGreen
+            '\033[38;5;23m',   # DeepSkyBlue4
+            '\033[38;5;24m',   # DeepSkyBlue4
+            '\033[38;5;25m',   # DeepSkyBlue4
+            '\033[38;5;26m',   # DodgerBlue3
+            '\033[38;5;27m',   # DodgerBlue2
+            '\033[38;5;28m',   # Green4
+            '\033[38;5;29m',   # SpringGreen4
+            '\033[38;5;30m',   # Turquoise4
+            '\033[38;5;31m',   # DeepSkyBlue3
+            '\033[38;5;32m',   # DeepSkyBlue3
+            '\033[38;5;33m',   # DodgerBlue1
+            '\033[38;5;34m',   # Green3
+            '\033[38;5;35m',   # SpringGreen3
+            '\033[38;5;36m',   # DarkCyan
+            '\033[38;5;37m',   # LightSeaGreen
+            '\033[38;5;38m',   # DeepSkyBlue2
+            '\033[38;5;39m',   # DeepSkyBlue1
+            # '\033[38;5;0m',    # Black
+            '\033[38;5;40m',   # Green3
+            '\033[38;5;41m',   # SpringGreen3
+            '\033[38;5;42m',   # SpringGreen2
+            '\033[38;5;43m',   # Cyan3
+            '\033[38;5;44m',   # DarkTurquoise
+            '\033[38;5;45m',   # Turquoise2
+            '\033[38;5;46m',   # Green1
+            '\033[38;5;47m',   # SpringGreen2
+            '\033[38;5;48m',   # SpringGreen1
+            '\033[38;5;49m',   # MediumSpringGreen
+            '\033[38;5;50m',   # Cyan2
+            '\033[38;5;51m',   # Cyan1
+            '\033[38;5;52m',   # DarkRed
+            '\033[38;5;53m',   # DeepPink4
+            '\033[38;5;54m',   # Purple4
+            '\033[38;5;55m',   # Purple4
+            '\033[38;5;56m',   # Purple3
+            '\033[38;5;57m',   # BlueViolet
+            '\033[38;5;58m',   # Orange4
+            '\033[38;5;59m',   # Grey37
+            '\033[38;5;60m',   # MediumPurple4
+            '\033[38;5;61m',   # SlateBlue3
+            '\033[38;5;62m',   # SlateBlue3
+            '\033[38;5;63m',   # RoyalBlue1
+            '\033[38;5;64m',   # Chartreuse4
+            '\033[38;5;65m',   # DarkSeaGreen4
+            '\033[38;5;66m',   # PaleTurquoise4
+            '\033[38;5;67m',   # SteelBlue
+            '\033[38;5;68m',   # SteelBlue3
+            '\033[38;5;69m',   # CornflowerBlue
+            '\033[38;5;70m',   # Chartreuse3
+            '\033[38;5;71m',   # DarkSeaGreen4
+            '\033[38;5;72m',   # CadetBlue
+            '\033[38;5;73m',   # CadetBlue
+            '\033[38;5;74m',   # SkyBlue3
+            '\033[38;5;75m',   # SteelBlue1
+            '\033[38;5;76m',   # Chartreuse3
+            '\033[38;5;77m',   # PaleGreen3
+            '\033[38;5;78m',   # SeaGreen3
+            '\033[38;5;79m',   # Aquamarine3
+            '\033[38;5;80m',   # MediumTurquoise
+            '\033[38;5;81m',   # SteelBlue1
+            '\033[38;5;82m',   # Chartreuse2
+            '\033[38;5;83m',   # SeaGreen2
+            '\033[38;5;84m',   # SeaGreen1
+            '\033[38;5;85m',   # SeaGreen1
+            '\033[38;5;86m',   # Aquamarine1
+            '\033[38;5;87m',   # DarkSlateGray2
+            '\033[38;5;88m',   # DarkRed
+            '\033[38;5;89m',   # DeepPink4
+            '\033[38;5;90m',   # DarkMagenta
+            '\033[38;5;91m',   # DarkMagenta
+            '\033[38;5;92m',   # DarkViolet
+            '\033[38;5;93m',   # Purple
+            '\033[38;5;94m',   # Orange4
+            '\033[38;5;95m',   # LightPink4
+            '\033[38;5;96m',   # Plum4
+            '\033[38;5;97m',   # MediumPurple3
+            '\033[38;5;98m',   # MediumPurple3
+            '\033[38;5;99m',   # SlateBlue1
+            '\033[38;5;100m',  # Yellow4
+            '\033[38;5;101m',  # Wheat4
+            '\033[38;5;102m',  # Grey53
+            '\033[38;5;103m',  # LightSlateGrey
+            '\033[38;5;104m',  # MediumPurple
+            '\033[38;5;105m',  # LightSlateBlue
+            '\033[38;5;106m',  # Yellow4
+            '\033[38;5;107m',  # DarkOliveGreen3
+            '\033[38;5;108m',  # DarkSeaGreen
+            '\033[38;5;109m',  # LightSkyBlue3
+            '\033[38;5;110m',  # LightSkyBlue3
+            '\033[38;5;111m',  # SkyBlue2
+            '\033[38;5;112m',  # Chartreuse2
+            '\033[38;5;113m',  # DarkOliveGreen3
+            '\033[38;5;114m',  # PaleGreen3
+            '\033[38;5;115m',  # DarkSeaGreen3
+            '\033[38;5;116m',  # DarkSlateGray3
+            '\033[38;5;117m',  # SkyBlue1
+            '\033[38;5;118m',  # Chartreuse1
+            '\033[38;5;119m',  # LightGreen
+            '\033[38;5;120m',  # LightGreen
+            '\033[38;5;121m',  # PaleGreen1
+            '\033[38;5;122m',  # Aquamarine1
+            '\033[38;5;123m',  # DarkSlateGray1
+            '\033[38;5;124m',  # Red3
+            '\033[38;5;125m',  # DeepPink4
+            '\033[38;5;126m',  # MediumVioletRed
+            '\033[38;5;127m',  # Magenta3
+            '\033[38;5;128m',  # DarkViolet
+            '\033[38;5;129m',  # Purple
+            '\033[38;5;130m',  # DarkOrange3
+            '\033[38;5;131m',  # IndianRed
+            '\033[38;5;142m',  # Gold3
+            '\033[38;5;143m',  # DarkKhaki
+            '\033[38;5;144m',  # NavajoWhite3
+            '\033[38;5;145m',  # Grey69
+            '\033[38;5;146m',  # LightSteelBlue3
+            '\033[38;5;147m',  # LightSteelBlue
+            '\033[38;5;148m',  # Yellow3
+            '\033[38;5;149m',  # DarkOliveGreen3
+            '\033[38;5;150m',  # DarkSeaGreen3
+            '\033[38;5;151m',  # DarkSeaGreen2
+            '\033[38;5;152m',  # LightCyan3
+            '\033[38;5;153m',  # LightSkyBlue1
+            '\033[38;5;154m',  # GreenYellow
+            '\033[38;5;155m',  # DarkOliveGreen2
+            '\033[38;5;156m',  # PaleGreen1
+            '\033[38;5;157m',  # DarkSeaGreen2
+            '\033[38;5;158m',  # DarkSeaGreen1
+            '\033[38;5;159m',  # PaleTurquoise1
+            '\033[38;5;160m',  # Red3
+            '\033[38;5;161m',  # DeepPink3
+            '\033[38;5;162m',  # DeepPink3
+            '\033[38;5;163m',  # Magenta3
+            '\033[38;5;164m',  # Magenta3
+            '\033[38;5;165m',  # Magenta2
+            '\033[38;5;166m',  # DarkOrange3
+            '\033[38;5;167m',  # IndianRed
+            '\033[38;5;168m',  # HotPink3
+            '\033[38;5;169m',  # HotPink2
+            '\033[38;5;170m',  # Orchid
+            '\033[38;5;171m',  # MediumOrchid1
+            '\033[38;5;172m',  # Orange3
+            '\033[38;5;173m',  # LightSalmon3
+            '\033[38;5;174m',  # LightPink3
+            '\033[38;5;175m',  # Pink3
+            '\033[38;5;176m',  # Plum3
+            '\033[38;5;177m',  # Violet
+            '\033[38;5;178m',  # Gold3
+            '\033[38;5;179m',  # LightGoldenrod3
+            '\033[38;5;180m',  # Tan
+            '\033[38;5;181m',  # MistyRose3
+            '\033[38;5;182m',  # Thistle3
+            '\033[38;5;183m',  # Plum2
+            '\033[38;5;184m',  # Yellow3
+            '\033[38;5;185m',  # Khaki3
+            '\033[38;5;186m',  # LightGoldenrod2
+            '\033[38;5;187m',  # LightYellow3
+            '\033[38;5;188m',  # Grey84
+            '\033[38;5;189m',  # LightSteelBlue1
+            '\033[38;5;190m',  # Yellow2
+            '\033[38;5;191m',  # DarkOliveGreen1
+            '\033[38;5;192m',  # DarkOliveGreen1
+            '\033[38;5;193m',  # DarkSeaGreen1
+            '\033[38;5;194m',  # Honeydew2
+            '\033[38;5;195m',  # LightCyan1
+            '\033[38;5;196m',  # Red1
+            '\033[38;5;197m',  # DeepPink2
+            '\033[38;5;198m',  # DeepPink1
+            '\033[38;5;199m',  # DeepPink1
+            '\033[38;5;200m',  # Magenta2
+            '\033[38;5;201m',  # Magenta1
+            '\033[38;5;202m',  # OrangeRed1
+            '\033[38;5;203m',  # IndianRed1
+            '\033[38;5;204m',  # IndianRed1
+            '\033[38;5;205m',  # HotPink
+            '\033[38;5;206m',  # HotPink
+            '\033[38;5;207m',  # MediumOrchid1
+            '\033[38;5;208m',  # DarkOrange
+            '\033[38;5;209m',  # Salmon1
+            '\033[38;5;210m',  # LightCoral
+            '\033[38;5;211m',  # PaleVioletRed1
+            '\033[38;5;212m',  # Orchid2
+            '\033[38;5;213m',  # Orchid1
+            '\033[38;5;214m',  # Orange1
+            '\033[38;5;215m',  # SandyBrown
+            '\033[38;5;216m',  # LightSalmon1
+            '\033[38;5;217m',  # LightPink1
+            '\033[38;5;218m',  # Pink1
+            '\033[38;5;219m',  # Plum1
+            '\033[38;5;220m',  # Gold1
+            '\033[38;5;221m',  # LightGoldenrod2
+            '\033[38;5;222m',  # LightGoldenrod2
+            '\033[38;5;223m',  # NavajoWhite1
+            '\033[38;5;224m',  # MistyRose1
+            '\033[38;5;225m',  # Thistle1
+            '\033[38;5;226m',  # Yellow1
+            '\033[38;5;227m',  # LightGoldenrod1
+            '\033[38;5;228m',  # Khaki1
+            '\033[38;5;229m',  # Wheat1
+            '\033[38;5;230m',  # Cornsilk1
+            '\033[38;5;231m',  # Grey100
+            '\033[38;5;232m',  # Grey3
+            '\033[38;5;233m',  # Grey7
+            '\033[38;5;234m',  # Grey11
+            '\033[38;5;235m',  # Grey15
+            '\033[38;5;236m',  # Grey19
+            '\033[38;5;237m',  # Grey23
+            '\033[38;5;238m',  # Grey27
+            '\033[38;5;239m',  # Grey30
+            '\033[38;5;240m',  # Grey35
+        ]
         self.colors_lst_map = {}
-        self.names = {}
-        self.hight = 20
+        self.names = []
+        self.height = 20
         self.width = 40
         self.colors_description_str = ""
         self.graph = ""
         self.series = []
         self.used_colors = []
-        self.init_first_lst_done = False 
+        self.init_first_lst_done = False
 
     def pick_color(self):
         """
@@ -49,14 +293,25 @@ def pick_color(self):
         self.colors.pop(0)
         return chosen_color
 
-    def create_graph(self, names=[], height=17, width=45, format='{:8.0f} MB'):
+    def create_graph(self, names=[], height=17, width=45, max_height=20, max_width=50, format='{:8.0f} MB'):
         """
         INPUT: a dctionary where the key is the data line name and value is the list (each list represent data line.)
             Example: ["eth0", "eth1", "eth2"]
         RETURN: Text Graph
         """
-        self.hight = height
-        self.width = width
+
+        if height == 0:
+            auto_height = max(10, len(names) * 2)
+            self.height = max_height if auto_height > max_height else auto_height
+        else:
+            self.height = height
+
+        if width == 0:
+            auto_width = max(len(name) for name in names)
+            self.width = max_width if auto_width > max_width else auto_width
+        else:
+            self.width = width
+
         self.names = names
 
         # if len(names) > len(self.colors):
@@ -66,7 +321,8 @@ def create_graph(self, names=[], height=17, width=45, format='{:8.0f} MB'):
         if len(names) > len(self.colors):
             index = len(self.colors)
             while len(self.colors) < len(names):
-                self.colors.append(asciichartpy.colored(char=list(names)[index] + " ", color=asciichartpy.black))
+                # self.colors.append(asciichartpy.colored(char=list(names)[index] + " ", color=asciichartpy.black))
+                self.colors.append(asciichartpy.black)
                 index +=1
 
         for name in names:
@@ -76,19 +332,19 @@ def create_graph(self, names=[], height=17, width=45, format='{:8.0f} MB'):
                 "color": color
             }
             self.used_colors.append(color)
-    
+
         self.colors_description()
 
         self.config = {
-        "colors": self.used_colors,
-        "offset": 3,             # axis offset from the left (min 2)
-        "padding": '       ',    # padding string for label formatting (can be overrided)
-        "height":  self.hight,   ## any height you want
-        "format": format
+            "colors": self.used_colors,
+            "offset": 3,             # axis offset from the left (min 2)
+            "padding": '       ',    # padding string for label formatting (can be overrided)
+            "height":  self.height,   ## any height you want
+            "format": format
         }
         graph =  asciichartpy.plot(series=self.series, cfg=self.config)
         self.graph = graph
-    
+
     def replace_lst(self, name, lst):
         if name not in self.names:
             raise Exception("List name not found")
@@ -100,43 +356,49 @@ def replace_lst(self, name, lst):
         self.series = []
         for name, info in self.colors_lst_map.items():
             self.series.append(info['lst'])
-        
+            self.used_colors.append(info['color'])
+
         # Update the graph with list update
         graph =  asciichartpy.plot(self.series, self.config)
         self.graph = graph
         return graph
 
-    def update_lst(self, name, item):
+    def update_lst(self, name, item, format):
         """
+        Update the list associated with a name and ensure used colors match the series.
         """
         if name not in self.names:
-            raise Exception("List name not found")
-        # if (not isinstance(item, int)) or (not isinstance(item, float)):
-            # raise Exception("List item should be int or float only")
+            color = self.pick_color()
+            self.colors_lst_map[name] = {
+                "lst": [],
+                "color": color
+            }
+            self.names.append(name)
 
-        # Update the list
-        self.colors_lst_map[name].get('lst').append(item)
+        self.colors_lst_map[name]['lst'].append(item)
 
-        # Keep the width
         if len(self.colors_lst_map[name]['lst']) > self.width:
             self.colors_lst_map[name]['lst'].pop(0)
-        
-        # Update the series list
-        for name, info in self.colors_lst_map.items():
-            self.series.append(info['lst'])
-        
-        # Put a "0" at the begining to show the full hight of the chart
+
+        # Update the series list and used colors
+        self.series = [info['lst'] for name, info in self.colors_lst_map.items()]
+        self.used_colors = [info['color'] for name, info in self.colors_lst_map.items()]
+
         if GlobalAttrs.start_graphs_with_zero:
             if not self.init_first_lst_done:
                 if len(self.colors_lst_map) > 0:
                     self.init_first_lst_done = True
-                    self.series[0].insert(0,0)
-            ## Maybe can have a counter to remove the inserted '0' [if needed.]
-            # else:
-            #     self.series[0].pop(0)
-        
-        # Update the graph with list update
-        graph =  asciichartpy.plot(self.series, self.config)
+                    self.series[0].insert(0, 0)
+
+        self.config = {
+            "colors": self.used_colors,
+            "offset": 3,
+            "padding": '       ',
+            "height": self.height,
+            "format": format
+        }
+
+        graph = asciichartpy.plot(self.series, self.config)
         self.graph = graph
         return graph
 
diff --git a/kubePtop/cli_args.py b/kubePtop/cli_args.py
new file mode 100644
index 0000000..a127a91
--- /dev/null
+++ b/kubePtop/cli_args.py
@@ -0,0 +1,348 @@
+import argparse
+from sys import getallocatedblocks
+import yaml
+import rich
+import os
+import logging
+from datetime import datetime
+from pathlib import Path
+from tabulate import tabulate
+from kubePtop.global_attrs import GlobalAttrs
+from kubePtop.dashboard_monitor import customDashboardMonitoring
+from kubePtop.command_run import commandRun
+from kubePtop.dashboard_yaml_loader import dashboardYamlLoader
+from kubePtop.command_yaml_loader import commandYamlLoader
+dashboard_yaml_loader = dashboardYamlLoader()
+command_yaml_loader = commandYamlLoader()
+custom_dashboard_monitoring = customDashboardMonitoring()
+custom_command_run = commandRun()
+class Cli():
+    def __init__(self):
+        self.default_cli_args = [
+            {
+                "name": "dashboard",
+                "default": "",
+                "cliArgument": {
+                    "enable": True,
+                    "short": "-D",
+                    "required": False,
+                    "description": "dashboard name to display"
+                }
+            },
+            {
+                "name": "command",
+                "default": "",
+                "cliArgument": {
+                    "enable": True,
+                    "short": "-C",
+                    "required": False,
+                    "description": "command name to display"
+                }
+            },
+            {
+                "name": "list-dashboards",
+                "default": ".*",
+                "cliArgument": {
+                    "enable": True,
+                    "short": "-ld",
+                    "required": False,
+                    "description": "List dasboards names"
+                }
+            },
+            {
+                "name": "list-commands",
+                "default": ".*",
+                "cliArgument": {
+                    "enable": True,
+                    "short": "-lc",
+                    "required": False,
+                    "description": "List commands names"
+                }
+            },
+            {
+                "name": "vhelp",
+                "default": ".*",
+                "cliArgument": {
+                    "enable": True,
+                    "short": "-vh",
+                    "required": False,
+                    "description": "List the variables cli arguments of the dashboard/command manifests"
+                }
+            },
+            {
+                "name": "debug",
+                "default": ".*",
+                "cliArgument": {
+                    "enable": True,
+                    "short": "-d",
+                    "required": False,
+                    "description": "Debug mode"
+                }
+            },
+            {
+                "name": "print-layout",
+                "default": ".*",
+                "cliArgument": {
+                    "enable": True,
+                    "short": "-pl",
+                    "required": False,
+                    "description": "Print empty layout structure"
+                }
+            },
+            {
+                "name": "version",
+                "default": ".*",
+                "cliArgument": {
+                    "enable": True,
+                    "short": "-V",
+                    "required": False,
+                    "description": "Print kptop version"
+                }
+            },
+        ]
+        self.variables = {}
+
+    def build_parser(self, variables):
+        parser = argparse.ArgumentParser(description='Process some CLI arguments.')
+        for var in variables:
+            if var['cliArgument']['enable']:
+                if var['name'] in ['vhelp', 'list-dashboards', 'list-commands', 'debug', 'print-layout', 'version']:
+                    parser.add_argument(
+                        f"--{var['name']}",
+                        var['cliArgument']['short'],
+                        required=var['cliArgument']['required'],
+                        action='store_true',
+                        help=var['cliArgument'].get('description', f'Specify the {var["name"]} variable value - default: "{var["default"]}"')
+                    )
+                else:
+                    parser.add_argument(
+                        f"--{var['name']}",
+                        var['cliArgument']['short'],
+                        required=var['cliArgument']['required'],
+                        default=var['default'],
+                        help=var['cliArgument'].get('description', f'Specify the {var["name"]} variable value - default: "{var["default"]}"')
+                    )
+        return parser
+
+
+    def _list_files_in_directory(self, directory_path):
+        out = {
+            "success": False,
+            "data": None,
+            "fail_reason": ""
+        }
+        try:
+            p = Path(directory_path)
+            files_info = [
+                {
+                    "name": file.stem,
+                    "creation_date": datetime.fromtimestamp(file.stat().st_ctime).strftime('%d-%m-%Y %H:%M:%S'),
+                    "modification_date": datetime.fromtimestamp(file.stat().st_mtime).strftime('%d-%m-%Y %H:%M:%S')
+                }
+                for file in p.iterdir() if file.is_file() and file.suffix in ['.yaml', '.yml']
+            ]
+            if len(files_info) < 1:
+                out['fail_reason'] = f"No files found in '{directory_path}'"
+                return out
+
+            out['data'] = files_info
+            out["success"] = True
+            return out
+        except FileNotFoundError as e:
+            out["fail_reason"] = f"Directory {directory_path} not found > {e}"
+            return out
+
+    def _load_file_content(self, directory_path, file_name):
+        out = {
+            "success": False,
+            "data": None,
+            "fail_reason": ""
+        }
+        yaml_extensions = ['.yaml', '.yml']
+
+        file_path = None
+        for ext in yaml_extensions:
+            try:
+                potential_path = Path(directory_path) / (file_name + ext)
+                if potential_path.exists():
+                    file_path = potential_path
+                    break
+            except Exception as e:
+                out["fail_reason"] = e
+                return out
+
+        if not file_path:
+            out["fail_reason"] = f"File '{file_name}'.yml||yaml is NOT Found in {directory_path}"
+            return out
+
+        try:
+            with open(file_path, 'r') as file:
+                out["data"] = file.read()
+                out["success"] = True
+        except Exception as e:
+            out["fail_reason"] = f"File is NOT Found"
+        return out
+
+
+    def run(self):
+        initial_parser = self.build_parser(self.default_cli_args)
+        # rich.print(initial_parser)
+        initial_args, unknown_args = initial_parser.parse_known_args()
+
+        if initial_args.command and initial_args.dashboard:
+            rich.print("\n[yellow bold]Can NOT specify '--dashboard' & '--command' together\n")
+            initial_parser.print_help()
+            exit(1)
+
+        if initial_args.list_dashboards and initial_args.list_commands:
+                    rich.print("\n[yellow bold]Can NOT specify '--list-dashboards' & '--list-commands' together\n")
+                    initial_parser.print_help()
+                    exit(1)
+
+
+
+        ################
+        # Show Version #
+        ################
+        if initial_args.version:
+            rich.print(GlobalAttrs.version)
+            exit(1)
+
+        ##############
+        # Debug Mode #
+        ##############
+        if initial_args.debug:
+            GlobalAttrs.debug = True
+
+        ###################
+        # List Dashboards #
+        ###################
+        if initial_args.list_dashboards:
+            check = self._list_files_in_directory(GlobalAttrs.default_dashboards_dir)
+            if not check['success']:
+                rich.print(f"Could NOT list dashboards.\n[yellow]{check['fail_reason']}\n")
+                exit(1)
+
+            table = [['DASHBOARD', 'CREATION TIME', 'UPDATE TIME']]
+
+            for file in check['data']:
+                row = [file['name'], file['creation_date'], file['modification_date']]
+                table.append(row)
+            out = tabulate(table, headers='firstrow', tablefmt='plain', showindex=False)
+            print(out)
+            print()
+            exit(0)
+
+        #################
+        # List Commands #
+        #################
+        if initial_args.list_commands:
+            check = self._list_files_in_directory(GlobalAttrs.default_commands_dir)
+            if not check['success']:
+                rich.print(f"Could NOT list commands.\n[yellow]{check['fail_reason']}\n")
+                exit(1)
+
+            table = [['COMMAND', 'CREATION TIME', 'UPDATE TIME']]
+
+            for file in check['data']:
+                row = [file['name'], file['creation_date'], file['modification_date']]
+                table.append(row)
+            out = tabulate(table, headers='firstrow', tablefmt='plain', showindex=False)
+            print(out)
+            print()
+            exit(0)
+
+        ##################
+        # Load Dashboard #
+        ##################
+        elif initial_args.dashboard:
+
+            # Load dashboard yaml file
+            check = self._load_file_content(GlobalAttrs.default_dashboards_dir, initial_args.dashboard)
+            if not check['success']:
+                rich.print(f"Dashboard is NOT found\n[yellow]{check['fail_reason']}\n")
+                exit(1)
+
+            # Parse and validate the dashboard yaml file
+            parsed_dashboard = dashboard_yaml_loader.load_dashboard_data(command_content_content=check['data'])
+
+            if not parsed_dashboard['success']:
+                logging.error(f"Failed to load dashboard: '{initial_args.dashboard}'")
+                logging.error(parsed_dashboard['fail_reason'])
+                exit(1)
+
+            variables = parsed_dashboard['data'].get('dashboard').get('variables', {})
+            # Combine default CLI args and dashboard variables
+            all_variables = self.default_cli_args + variables
+            # Rebuild the parser with all variables
+            final_parser = self.build_parser(all_variables)
+            # Parse all arguments with the final parser
+            final_args, unknown_args = initial_parser.parse_known_args()
+            # Store the arguments in the variables dictionary
+            args_dict = vars(final_args)
+
+            if args_dict['vhelp']:
+                final_parser.print_help()
+                exit(0)
+
+            for arg, value in args_dict.items():
+                self.variables[arg] = value
+
+            args = final_parser.parse_args()
+            args_dict = vars(args)
+            for arg, value in args_dict.items():
+                if value == 'ALL':
+                    value = ".*"
+                self.variables[arg] = value
+
+            custom_dashboard_monitoring.build_custom_dashboard(dashboard_data=parsed_dashboard, dashboard_variables=self.variables, print_layout=initial_args.print_layout)
+
+        ################
+        # Load Command #
+        ################
+        elif initial_args.command:
+            # Load command yaml file
+            check = self._load_file_content(GlobalAttrs.default_commands_dir, initial_args.command)
+            if not check['success']:
+                rich.print(f"Command is NOT found\n[yellow]{check['fail_reason']}\n")
+                exit(1)
+
+            # Parse and validate the command yaml file
+            parsed_command = command_yaml_loader.load_command_data(command_content_content=check['data'])
+            if not parsed_command['success']:
+                logging.error(f"Failed to load command: '{initial_args.command}'")
+                logging.error(parsed_command['fail_reason'])
+                exit(1)
+
+            variables = parsed_command['data'].get('command').get('variables', [])
+            if variables:
+                # Combine default CLI args and dashboard variables
+                all_variables = self.default_cli_args + variables
+            else:
+                all_variables = self.default_cli_args
+
+            # Rebuild the parser with all variables
+            final_parser = self.build_parser(all_variables)
+            # Parse all arguments with the final parser
+            final_args, unknown_args = initial_parser.parse_known_args()
+            # Store the arguments in the variables dictionary
+            args_dict = vars(final_args)
+
+            if args_dict['vhelp']:
+                final_parser.print_help()
+                exit(0)
+
+            for arg, value in args_dict.items():
+                self.variables[arg] = value
+
+            args = final_parser.parse_args()
+            args_dict = vars(args)
+            for arg, value in args_dict.items():
+                if value == 'ALL':
+                    value = ".*"
+                self.variables[arg] = value
+
+            custom_command_run.run_custom_command(command_data=parsed_command, command_variables=self.variables)
+        elif unknown_args:
+            rich.print(f"[yellow]ERROR -- Unknown args !!    {' '.join(unknown_args)}")
+            initial_parser.print_usage()
diff --git a/kubePtop/colors.py b/kubePtop/colors.py
index e625f19..0292c3d 100644
--- a/kubePtop/colors.py
+++ b/kubePtop/colors.py
@@ -1,4 +1,3 @@
-
 class Bcolors:
     def __init__(self):
         self.HEADER = '\033[95m'
@@ -10,4 +9,4 @@ def __init__(self):
         self.BOLD = '\033[1m'
         self.UNDERLINE = '\033[4m'
         self.GRAY = "\033[1;30;40m"
-        self.GRAY = "\033[90m"
\ No newline at end of file
+        self.GRAY = "\033[90m"
diff --git a/kubePtop/command_run.py b/kubePtop/command_run.py
new file mode 100644
index 0000000..4a207a0
--- /dev/null
+++ b/kubePtop/command_run.py
@@ -0,0 +1,204 @@
+import re
+import rich
+import os
+from tabulate import tabulate
+import logging
+from kubePtop.global_attrs import GlobalAttrs
+from kubePtop.session import PrometheusAPI
+# from kubePtop.ascii_graph import AsciiGraph
+from kubePtop.helper import Helper
+helper_ = Helper()
+
+from kubePtop.logging import Logging
+
+class commandRun(PrometheusAPI):
+    def __init__(self):
+        super().__init__()
+        self.layout_list = []
+        self.data = {
+            "graphs": {}
+        }
+        self.layout = None
+        self.variables = {}
+
+    def run_query(self, query):
+        if GlobalAttrs.env_connection_method == 'prometheus_endpoint':
+            return self.run_query_prometheus_endpoint(query)
+        elif GlobalAttrs.env_connection_method == 'pod_portForward':
+            if self.core_v1 is None:
+                self.K8s_authenticate()
+            return self.run_query_pod_portForward(query)
+
+        return query
+
+    def run_custom_command(self, command_data, command_variables):
+        self.variables = command_variables
+        command_dct = command_data['data']['command']
+        if command_dct['execute']['type'] == 'advancedTable':
+            self.build_advanced_table_command(name=command_dct['name'], layout_box_name=None, advanced_table_options=command_dct['execute'].get('advancedTableOptions', {}), metric_unit='kb', columns=command_dct['execute'].get('advancedTableColumns', {}), custom_key=command_dct['execute']['custom_key'])
+
+
+    def get_metric_data(self, metric, custom_key=None, evaluate_cli_argument_variables=False, value_from_label=""):
+        out = {
+            "success": False,
+            "data": None,
+            "fail_reason": "",
+            "metric": ""
+        }
+
+        # Replace variables
+        metric = self.replace_cli_argument_variable(metric)
+        out['metric'] = metric
+        # Run Metric
+        metric_result = self.run_query(metric)
+
+        if not metric_result.get('status') == 'success':
+            out['fail_reason'] = "could not get metric value (Possible Syntax Error)"
+            return out
+
+        if not metric_result.get('data').get('result'):
+            out['fail_reason'] = "metric did not return any data"
+            return out
+
+        dct = {}
+        for i in metric_result['data']['result']:
+            labels = i['metric']
+
+            key = ""
+            if custom_key:
+                try:
+                    # key = str(eval(custom_key))
+                    key = helper_.safe_eval(custom_key, labels)
+                except KeyError as e:
+                    out['fail_reason'] = f"Label NOT found {e} --> Query: {metric}"
+                    # key = f"Label NOT found: {e}"
+                    # key = str(eval(custom_key.replace(e, 'not_found')))
+                except SyntaxError as e:
+                    out['fail_reason'] = f"Python Syntax Error: {e} --> {custom_key}"
+                    key = "Python Syntax Error"
+
+                except Exception as e:
+                    out['fail_reason'] = f"failed to replace the key with custom_key: {e}"
+                    key = str(e)
+
+            else:
+                key = str(i['metric'])
+
+            if value_from_label:
+                dct[key] = {
+                    "timestamp":i['value'][0],
+                    "value":i['metric'].get(value_from_label, 'label_not_found'),
+                }
+            else:
+                dct[key] = {
+                    "timestamp":i['value'][0],
+                    "value":i['value'][1]
+                }
+        out['data'] = dct
+        out['success'] = True
+        return out
+
+    def _find_variables_in_query(self, query):
+        # Find all variables in the form $VARIABLE
+        variables = re.findall(r'\$\w+', query)
+        return variables
+
+    def replace_cli_argument_variable(self, query):
+        out = {
+            "success": False,
+            "data": None,
+            "fail_reason": ""
+        }
+        found_variables = self._find_variables_in_query(query)
+        if found_variables:
+            for variable in found_variables:
+                if variable[1:] in self.variables:
+                    # Replace the variable in the query string
+                    query = query.replace(variable, self.variables[variable[1:]])
+        return query
+
+    def build_advanced_table_command(self, name, layout_box_name, advanced_table_options, metric_unit, columns, custom_key=None):
+
+        if advanced_table_options:
+            table_type_ = advanced_table_options.get("tableType", 'plain')
+            # show_value_ = advanced_table_options.get("showValue", True)
+            header_upper_case_ = advanced_table_options.get("headersUppercase", True)
+            auto_convert_value_ = advanced_table_options.get("autoConvertValue", True)
+            show_table_index_ = advanced_table_options.get("showTableIndex", True)
+            update_interval_ = advanced_table_options.get("updateIntervalSeconds", 5)
+        else:
+            table_type_ = 'plain'
+            # show_value_ = True
+            header_upper_case_ = True
+            auto_convert_value_ = True
+            show_table_index_ = True
+            update_interval_ = 5
+
+        box_name = name
+        data = {}
+
+        columns_dct = {}
+        for column in columns:
+            key = next(iter(column))
+            new_dct = {k: v for k, v in column.items() if k != key}
+            columns_dct[key] = new_dct
+
+        header = list(columns_dct.keys())
+        header.insert(0, 'name')
+
+        if header_upper_case_:
+            header = [key.upper() for key in header]
+
+        table = [header]
+        for column, column_info in columns_dct.items():
+            # metric_data = self.get_metric_data(column_info['metric'], custom_key=custom_key)
+        #     metric_data = self.get_metric_data(column_info['metric'], custom_key=custom_key, value_from_label=column_info.get('valueFromLabel', ''))
+
+
+            # if not metric_data['success']:
+            #     rich.print(f"[red]Failed to get data from query 'total_value_metric': [bold]{metric_data['fail_reason']}[/bold][/red]\n\n[bold]METRIC:[/bold]\n[grey53]{metric_data['metric']}")
+            #     exit(1)
+
+        #     for name, value in metric_data['data'].items():
+        #         value_ = float(value['value'])
+        #         if auto_convert_value_:
+        #             value_ = helper_.convert_data_unit(value=value_, metric_unit=column_info['metricUnit'])
+        #         try:
+        #             data[name][column] = value_
+        #         except KeyError:
+        #             data[name] = {
+        #                 column: value_
+        #             }
+
+        # for name, value in data.items():
+        #     row = [name] + [value.get(col, '?') for col in columns_dct.keys()]  # Ensure order matches headers
+        #     table.append(row)
+            metric_data = self.get_metric_data(column_info['metric'], custom_key=custom_key, value_from_label=column_info.get('valueFromLabel', ''))
+
+            if not metric_data['success']:
+                rich.print(f"[red]Failed to get data from query 'total_value_metric': [bold]{metric_data['fail_reason']}[/bold][/red]\n\n[bold]METRIC:[/bold]\n[grey53]{metric_data['metric']}")
+                exit(1)
+
+            for name, value in metric_data['data'].items():
+                try:
+                    value_ = float(value['value'])
+                    if auto_convert_value_:
+                        value_ = helper_.convert_data_unit(value=value_, metric_unit=column_info['metricUnit'])
+                except:
+                    value_ = value['value']
+
+                try:
+                    data[name][column] = value_
+                except KeyError:
+                    data[name] = {
+                        column: value_
+                    }
+
+        for name, value in data.items():
+            row = [name] + [value.get(col, '?') for col in columns_dct.keys()]  # Ensure order matches headers
+            table.append(row)
+
+
+
+        out = tabulate(table, headers='firstrow', tablefmt=table_type_, showindex=show_table_index_)
+        rich.print(out)
diff --git a/kubePtop/command_yaml_loader.py b/kubePtop/command_yaml_loader.py
new file mode 100644
index 0000000..22a8e43
--- /dev/null
+++ b/kubePtop/command_yaml_loader.py
@@ -0,0 +1,749 @@
+import os
+import yaml
+import json
+from cerberus import Validator
+import rich
+class commandYamlLoader:
+    def __init__(self) -> None:
+        self.allowed_metric_unit_types = [
+            'None',
+            'kb',
+            'byte',
+            'mb',
+            'gb',
+            'tb',
+            'seconds',
+            'percentage'
+        ]
+
+    def validate_command_schema(self, dashboard_yaml_data):
+
+        schema_dct = {
+            'command': {
+                'type': 'dict',
+                'schema': {
+                    'name': {
+                        'type': 'string',
+                        'required': True
+                    },
+                    'description': {
+                        'type': 'string',
+                        'required': True
+                    },
+                    'variables': {
+                        'type': 'list',
+                        'schema': {
+                            'type': 'dict',
+                            'schema': {
+                                'name': {
+                                    'type': 'string',
+                                    'required': True
+                                },
+                                'default': {
+                                    'type': 'string',
+                                    'required': True
+                                },
+                                'cliArgument': {
+                                    'type': 'dict',
+                                    'schema': {
+                                        'enable': {
+                                            'type': 'boolean',
+                                            'required': True
+                                        },
+                                        'short': {
+                                            'type': 'string',
+                                            'required': True
+                                        },
+                                        'required': {
+                                            'type': 'boolean',
+                                            'required': True
+                                        },
+                                        'description': {
+                                            'type': 'string',
+                                            'required': False
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    'execute': {
+                        'type': 'dict',
+                        'schema': {
+                            'type': {
+                                'type': 'string',
+                                'required': True,
+                                'allowed': [
+                                    "advancedTable"
+                                ]
+                            },
+                            'advancedTableColumns': {
+                                'type': 'list',
+                                'required': False,
+                                'schema': {
+                                    'type': 'dict',
+                                    'required': True,
+                                    'allow_unknown': True,
+                                    'schema': {
+                                        'metric': {
+                                            'type': 'string',
+                                            'required': True
+                                        },
+                                        'metricUnit': {
+                                            'type': 'string',
+                                            'required': False,
+                                            'default': 'None',
+                                            'allowed': self.allowed_metric_unit_types
+                                        },
+                                        'valueFromLabel': {
+                                            'type': 'string',
+                                            'required': False,
+                                            'default': "",
+                                        }
+                                    }
+                                }
+                            },
+                            'custom_key': {
+                                'type': 'string',
+                                'required': False,
+                                'default': ""
+                            },
+                            'advancedTableOptions': {
+                                'type': 'dict',
+                                'schema': {
+                                    'tableType': {
+                                        'type': 'string',
+                                        'required': False,
+                                        'default': 'plain',
+                                        'allowed': [
+                                            'plain',
+                                            'simple',
+                                            'github',
+                                            'grid',
+                                            'simple_grid',
+                                            'rounded_grid',
+                                            'heavy_grid',
+                                            'mixed_grid',
+                                            'double_grid',
+                                            'fancy_grid',
+                                            'outline',
+                                            'simple_outline',
+                                            'rounded_outline',
+                                            'heavy_outline',
+                                            'mixed_outline',
+                                            'double_outline',
+                                            'fancy_outline',
+                                            'pipe',
+                                            'orgtbl',
+                                            'asciidoc',
+                                            'jira',
+                                            'presto',
+                                            'pretty',
+                                            'psql',
+                                            'rst',
+                                            'mediawiki',
+                                            'moinmoin',
+                                            'youtrack',
+                                            'html',
+                                            'unsafehtml',
+                                            'latex',
+                                            'latex_raw',
+                                            'latex_booktabs',
+                                            'latex_longtable',
+                                            'textile',
+                                            'tsv',
+                                        ]
+                                    },
+                                    'headersUppercase': {
+                                        'type': 'boolean',
+                                        'required': True,
+                                        'default': True,
+                                    },
+                                    'autoConvertValue': {
+                                        'type': 'boolean',
+                                        'required': True,
+                                        'default': False,
+                                    },
+                                    'showTableIndex': {
+                                        'type': 'boolean',
+                                        'required': True,
+                                        'default': False,
+                                    },
+                                    'updateIntervalSeconds': {
+                                        'type': 'integer',
+                                        'required': True,
+                                        'default': 5,
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        # schema_dct = {
+
+        #     "dashboard": {
+        #         'type': 'dict',
+        #         'required': True,
+        #         'schema': {
+        #             "name": {
+        #                 'type': 'string',
+        #                 'required': True,
+        #             },
+        #             "description": {
+        #                 'type': 'string',
+        #                 'required': False,
+        #                 'default': ""
+        #             },
+        #             "layout": {
+        #                 'type': 'dict',
+        #                 'required': True,
+        #                 'schema': {
+        #                     'splitMode': {
+        #                         "type": "string",
+        #                         'required': False,
+        #                         'default': 'row',
+        #                         'allowed': [
+        #                             'row',
+        #                             'column'
+        #                         ]
+        #                     },
+        #                     'fullScreen': {
+        #                         "type": "boolean",
+        #                         'required': False,
+        #                         'default': True,
+        #                         'allowed': [
+        #                             True,
+        #                             False
+        #                         ]
+        #                     },
+        #                     "header": {
+        #                         'type': 'dict',
+        #                         'required': False,
+        #                         'schema': {
+        #                             'enable': {
+        #                                 "type": "boolean",
+        #                                 'required': False,
+        #                                 'default': False
+        #                             },
+        #                             'size': {
+        #                                 "type": "integer",
+        #                                 'required': False,
+        #                                 'default': 0
+        #                             },
+        #                             'ratio': {
+        #                                 "type": "integer",
+        #                                 'required': True,
+        #                                 'default': 1
+        #                             },
+        #                         }
+        #                     },
+        #                     'body': {
+        #                             'type': 'dict',
+        #                             'schema': {
+        #                                 'boxes': {
+        #                                     'type': 'dict',
+        #                                     'schema': {
+        #                                         'left': {
+        #                                             'type': 'dict',
+        #                                             'schema': {
+        #                                                 'enable': {
+        #                                                     'type': 'boolean',
+        #                                                     'required': True
+        #                                                 },
+        #                                                 'size': {
+        #                                                     'type': 'integer',
+        #                                                     'required': False,
+        #                                                     'default': 0
+        #                                                 },
+        #                                                 'ratio': {
+        #                                                     'type': 'integer',
+        #                                                     'required': False,
+        #                                                     'default': 1
+        #                                                 },
+        #                                                 'split_mode': {
+        #                                                     'type': 'string',
+        #                                                     'required': False,
+        #                                                     'default': 'row',
+        #                                                     'allowed': [
+        #                                                         'row',
+        #                                                         'column'
+        #                                                     ]
+        #                                                 },
+        #                                                 'split': {
+        #                                                     'type': 'dict',
+        #                                                     'required': False,
+        #                                                     'allow_unknown': True,
+        #                                                     'schema': {
+        #                                                         'size': {
+        #                                                             'type': 'integer',
+        #                                                             'required': False,
+        #                                                             'default': 0
+        #                                                         },
+        #                                                         'ratio': {
+        #                                                             'type': 'integer',
+        #                                                             'required': False,
+        #                                                             'default': 1
+        #                                                         }
+        #                                                     }
+        #                                                 }
+        #                                             }
+        #                                         },
+        #                                         'middle': {
+        #                                             'type': 'dict',
+        #                                             'schema': {
+        #                                                 'enable': {
+        #                                                     'type': 'boolean',
+        #                                                     'required': True
+        #                                                 },
+        #                                                 'size': {
+        #                                                     'type': 'integer',
+        #                                                     'required': False,
+        #                                                     'default': 0
+        #                                                 },
+        #                                                 'ratio': {
+        #                                                     'type': 'integer',
+        #                                                     'required': False,
+        #                                                     'default': 1
+        #                                                 },
+        #                                                 'split_mode': {
+        #                                                     'type': 'string',
+        #                                                     'required': False,
+        #                                                     'default': 'row',
+        #                                                     'allowed': [
+        #                                                         'row',
+        #                                                         'column'
+        #                                                     ]
+        #                                                 },
+        #                                                 'split': {
+        #                                                     'type': 'dict',
+        #                                                     'required': False,
+        #                                                     'allow_unknown': True,
+        #                                                     'schema': {
+        #                                                         'size': {
+        #                                                             'type': 'integer',
+        #                                                             'required': False,
+        #                                                             'default': 0
+        #                                                         },
+        #                                                         'ratio': {
+        #                                                             'type': 'integer',
+        #                                                             'required': False,
+        #                                                             'default': 1
+        #                                                         }
+        #                                                     }
+        #                                                 }
+        #                                             }
+        #                                         },
+        #                                         'right': {
+        #                                             'type': 'dict',
+        #                                             'schema': {
+        #                                                 'enable': {
+        #                                                     'type': 'boolean',
+        #                                                     'required': True
+        #                                                 },
+        #                                                 'size': {
+        #                                                     'type': 'integer',
+        #                                                     'required': False,
+        #                                                     'default': 0
+        #                                                 },
+        #                                                 'ratio': {
+        #                                                     'type': 'integer',
+        #                                                     'required': False,
+        #                                                     'default': 1
+        #                                                 },
+        #                                                 'split_mode': {
+        #                                                     'type': 'string',
+        #                                                     'required': False,
+        #                                                     'default': 'row',
+        #                                                     'allowed': [
+        #                                                         'row',
+        #                                                         'column'
+        #                                                     ]
+        #                                                 },
+        #                                                 'split': {
+        #                                                     'type': 'dict',
+        #                                                     'required': False,
+        #                                                     'allow_unknown': True,
+        #                                                     'schema': {
+        #                                                         'size': {
+        #                                                             'type': 'integer',
+        #                                                             'required': False,
+        #                                                             'default': 0
+        #                                                         },
+        #                                                         'ratio': {
+        #                                                             'type': 'integer',
+        #                                                             'required': False,
+        #                                                             'default': 1
+        #                                                         }
+        #                                                     }
+        #                                                 }
+        #                                             }
+        #                                         }
+        #                                     }
+        #                                 }
+        #                             }
+        #                         },
+        #                 }
+        #             },
+        #             'variables': {
+        #                 'type': 'list',
+        #                 'schema': {
+        #                     'type': 'dict',
+        #                     'schema': {
+        #                         'name': {
+        #                             'type': 'string',
+        #                             'required': True
+        #                         },
+        #                         'default': {
+        #                             'type': 'string',
+        #                             'required': True,
+        #                         },
+        #                         'cliArgument': {
+        #                             'type': 'dict',
+        #                             'schema': {
+        #                                 'enable': {
+        #                                     'type': 'boolean',
+        #                                     'required': True
+        #                                 },
+        #                                 'short': {
+        #                                     'type': 'string',
+        #                                     'required': True,
+        #                                     'regex': r'^-\w{1,2}$'
+        #                                 },
+        #                                 'required': {
+        #                                     'type': 'boolean',
+        #                                     'default': True,
+        #                                     'required': False
+        #                                 },
+        #                                 'description': {
+        #                                     'type': 'string',
+        #                                     'required': False
+        #                                 }
+        #                             }
+        #                         }
+        #                     }
+        #                 }
+        #             },
+        #             'visualization': {
+        #                     'type': 'list',
+        #                     'schema': {
+        #                         'type': 'dict',
+        #                         'allow_unknown': True,
+        #                         'schema': {
+        #                             'name': {
+        #                                 'type': 'string',
+        #                                 'required': True
+        #                             },
+        #                             'box': {
+        #                                 'type': 'string',
+        #                                 'required': True
+        #                             },
+        #                             'enable': {
+        #                                 'type': 'boolean',
+        #                                 'required': False,
+        #                                 'default': True
+        #                             },
+        #                             'type': {
+        #                                 'type': 'string',
+        #                                 'required': True,
+        #                                 'allowed': [
+        #                                     'asciiGraph',
+        #                                     'progressBarList',
+        #                                     'simpleTable',
+        #                                     'advancedTable',
+        #                                 ]
+        #                             },
+        #                             'metricUnit': {
+        #                                 'type': 'string',
+        #                                 'required': True,
+        #                                 'allowed': [
+        #                                     'byte',
+        #                                     'kb',
+        #                                     'mb',
+        #                                     'gb',
+        #                                     'tb',
+        #                                     'seconds'
+        #                                 ]
+        #                             },
+        #                             'metric': {
+        #                                 'type': 'string'
+        #                             },
+        #                             'custom_key': {
+        #                                 'type': 'string',
+        #                                 'required': False,
+        #                             },
+        #                             'asciiGraphOptions': {
+        #                                 'type': 'dict',
+        #                                 'schema': {
+        #                                     'height': {
+        #                                         'type': 'integer',
+        #                                         'required': False,
+        #                                         'default': 0,
+        #                                     },
+        #                                     'width': {
+        #                                         'type': 'integer',
+        #                                         'required': False,
+        #                                         'default': 80,
+        #                                     },
+        #                                     'maxHeight': {
+        #                                         'type': 'integer',
+        #                                         'required': False,
+        #                                         'default': 17,
+        #                                     },
+        #                                     'maxWidth': {
+        #                                         'type': 'integer',
+        #                                         'required': False,
+        #                                         'default': 45,
+        #                                     },
+        #                                     'updateIntervalSeconds': {
+        #                                         'type': 'integer',
+        #                                         'required': False,
+        #                                         'default': 5,
+        #                                     }
+        #                                 }
+        #                             },
+        #                             'progressBarListOptions': {
+        #                                 'type': 'dict',
+        #                                 'schema': {
+        #                                     'maxItemsCount': {
+        #                                         'type': 'integer',
+        #                                         'required': False,
+        #                                         'default': 0,
+        #                                     },
+        #                                     'lineBreak': {
+        #                                         'type': 'boolean',
+        #                                         'required': False,
+        #                                         'default': True,
+        #                                     },
+        #                                     'showBarPercentage': {
+        #                                         'type': 'boolean',
+        #                                         'required': False,
+        #                                         'default': True,
+        #                                     },
+        #                                     'barWidth': {
+        #                                         'type': 'integer',
+        #                                         'required': False,
+        #                                         'default': 25,
+        #                                     },
+        #                                     'updateIntervalSeconds': {
+        #                                         'type': 'integer',
+        #                                         'required': False,
+        #                                         'default': 5,
+        #                                     }
+        #                                 }
+        #                             },
+        #                             'simpleTableOptions': {
+        #                                 'type': 'dict',
+        #                                 'schema': {
+        #                                     'tableType': {
+        #                                         'type': 'string',
+        #                                         'required': False,
+        #                                         'default': 'plain',
+        #                                         'allowed': [
+        #                                             'plain',
+        #                                             'simple',
+        #                                             'github',
+        #                                             'grid',
+        #                                             'simple_grid',
+        #                                             'rounded_grid',
+        #                                             'heavy_grid',
+        #                                             'mixed_grid',
+        #                                             'double_grid',
+        #                                             'fancy_grid',
+        #                                             'outline',
+        #                                             'simple_outline',
+        #                                             'rounded_outline',
+        #                                             'heavy_outline',
+        #                                             'mixed_outline',
+        #                                             'double_outline',
+        #                                             'fancy_outline',
+        #                                             'pipe',
+        #                                             'orgtbl',
+        #                                             'asciidoc',
+        #                                             'jira',
+        #                                             'presto',
+        #                                             'pretty',
+        #                                             'psql',
+        #                                             'rst',
+        #                                             'mediawiki',
+        #                                             'moinmoin',
+        #                                             'youtrack',
+        #                                             'html',
+        #                                             'unsafehtml',
+        #                                             'latex',
+        #                                             'latex_raw',
+        #                                             'latex_booktabs',
+        #                                             'latex_longtable',
+        #                                             'textile',
+        #                                             'tsv',
+        #                                         ]
+        #                                     },
+        #                                     'showValue': {
+        #                                         'type': 'boolean',
+        #                                         'required': True,
+        #                                         'default': True,
+        #                                     },
+        #                                     'headersUppercase': {
+        #                                         'type': 'boolean',
+        #                                         'required': True,
+        #                                         'default': True,
+        #                                     },
+        #                                     'autoConvertValue': {
+        #                                         'type': 'boolean',
+        #                                         'required': True,
+        #                                         'default': False,
+        #                                     },
+        #                                     'showTableIndex': {
+        #                                         'type': 'boolean',
+        #                                         'required': True,
+        #                                         'default': False,
+        #                                     },
+        #                                     'updateIntervalSeconds': {
+        #                                         'type': 'integer',
+        #                                         'required': True,
+        #                                         'default': 5,
+        #                                     }
+        #                                 }
+        #                             },
+        #                             'advancedTableColumns': {
+        #                                 'type': 'list',
+        #                                 'required': False,
+        #                                 'schema': {
+        #                                     'type': 'dict',
+        #                                     'required': True,
+        #                                     'allow_unknown': True,
+        #                                     'schema': {
+        #                                         'metric': {
+        #                                             'type': 'string',
+        #                                             'required': True
+        #                                         },
+        #                                         'metricUnit': {
+        #                                             'type': 'string',
+        #                                             'required': True,
+        #                                             'allowed': [
+        #                                                 'kb',
+        #                                                 'byte',
+        #                                                 'mb',
+        #                                                 'gb',
+        #                                                 'tb',
+        #                                                 'seconds',
+        #                                             ]
+        #                                         }
+        #                                     }
+        #                                 }
+        #                             },
+        #                             'advancedTableOptions': {
+        #                                 'type': 'dict',
+        #                                 'schema': {
+        #                                     'tableType': {
+        #                                         'type': 'string',
+        #                                         'required': False,
+        #                                         'default': 'plain',
+        #                                         'allowed': [
+        #                                             'plain',
+        #                                             'simple',
+        #                                             'github',
+        #                                             'grid',
+        #                                             'simple_grid',
+        #                                             'rounded_grid',
+        #                                             'heavy_grid',
+        #                                             'mixed_grid',
+        #                                             'double_grid',
+        #                                             'fancy_grid',
+        #                                             'outline',
+        #                                             'simple_outline',
+        #                                             'rounded_outline',
+        #                                             'heavy_outline',
+        #                                             'mixed_outline',
+        #                                             'double_outline',
+        #                                             'fancy_outline',
+        #                                             'pipe',
+        #                                             'orgtbl',
+        #                                             'asciidoc',
+        #                                             'jira',
+        #                                             'presto',
+        #                                             'pretty',
+        #                                             'psql',
+        #                                             'rst',
+        #                                             'mediawiki',
+        #                                             'moinmoin',
+        #                                             'youtrack',
+        #                                             'html',
+        #                                             'unsafehtml',
+        #                                             'latex',
+        #                                             'latex_raw',
+        #                                             'latex_booktabs',
+        #                                             'latex_longtable',
+        #                                             'textile',
+        #                                             'tsv',
+        #                                         ]
+        #                                     },
+        #                                     'headersUppercase': {
+        #                                         'type': 'boolean',
+        #                                         'required': True,
+        #                                         'default': True,
+        #                                     },
+        #                                     'autoConvertValue': {
+        #                                         'type': 'boolean',
+        #                                         'required': True,
+        #                                         'default': False,
+        #                                     },
+        #                                     'showTableIndex': {
+        #                                         'type': 'boolean',
+        #                                         'required': True,
+        #                                         'default': False,
+        #                                     },
+        #                                     'updateIntervalSeconds': {
+        #                                         'type': 'integer',
+        #                                         'required': True,
+        #                                         'default': 5,
+        #                                     }
+        #                                 }
+        #                             }
+        #                         }
+        #                     }
+        #                 }
+        #         }
+        #     },
+        # }
+        # return schema_dct
+
+        v = Validator(schema_dct)
+        v.validate(dashboard_yaml_data)
+        if v.errors:
+            import re
+            yaml_errors = yaml.dump(v.errors, default_flow_style=False)
+
+            # Regex to find "unknown field" and "must be of"
+            yaml_errors = re.sub(r'(unknown field)', '[red]\\1[/red]', yaml_errors)
+            yaml_errors = re.sub(r'(must be of.*)', '[red]\\1[/red]', yaml_errors)
+            yaml_errors = re.sub(r'(unallowed value.*)', '[red]\\1[/red]', yaml_errors)
+            yaml_errors = re.sub(r'(required field.*)', '[red]\\1[/red]', yaml_errors)
+            yaml_errors = re.sub(r'(null value not allowe.*)', '[red]\\1[/red]', yaml_errors)
+
+            print("ERROR -- Please fix the following in the dashboard YAML file:\n")
+            rich.print("[bold]" + yaml_errors)
+            exit(1)
+
+
+    def load_command_data(self, command_content_content):
+        out = {
+            "success": False,
+            "data": None,
+            "fail_reason": ""
+        }
+
+        # Read the file
+        try:
+            out['data'] = yaml.safe_load(command_content_content)
+        except Exception as e:
+            out['fail_reason'] = f"Failed to parse the command file content > {e}"
+            return out
+
+        # Yaml Schema validation
+        self.validate_command_schema(out['data'])
+
+        out['success'] = True
+        return out
diff --git a/kubePtop/dashboard_monitor.py b/kubePtop/dashboard_monitor.py
new file mode 100644
index 0000000..4992d8a
--- /dev/null
+++ b/kubePtop/dashboard_monitor.py
@@ -0,0 +1,716 @@
+import argparse
+import re
+from math import floor
+import time
+import threading
+import rich
+from rich.live import Live
+# from rich.table import Table
+from rich.panel import Panel
+from rich.progress import SpinnerColumn, Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn
+from rich.layout import Layout
+import os
+from tabulate import tabulate
+import yaml, json
+import logging
+import ast
+from itertools import islice
+from rich.console import Console, Group
+from rich.rule import Rule
+from rich.console import Console
+from rich.markdown import Markdown
+from rich.text import Text
+import traceback
+
+from kubePtop.global_attrs import GlobalAttrs
+from kubePtop.session import PrometheusAPI
+from kubePtop.ascii_graph import AsciiGraph
+from kubePtop.helper import Helper
+helper_ = Helper()
+
+from kubePtop.logging import Logging
+
+class customDashboardMonitoring(PrometheusAPI):
+    def __init__(self):
+        super().__init__()
+        self.layout_list = []
+        self.data = {
+            "graphs": {}
+        }
+        self.layout = None
+        self.variables = {}
+        self.threads = {}
+
+    def run_query(self, query):
+        if GlobalAttrs.env_connection_method == 'prometheus_endpoint':
+            return self.run_query_prometheus_endpoint(query)
+        elif GlobalAttrs.env_connection_method == 'pod_portForward':
+            if self.core_v1 is None:
+                self.K8s_authenticate()
+            return self.run_query_pod_portForward(query)
+
+        return query
+
+    # def build_parser(self, variables):
+    #     parser = argparse.ArgumentParser(description='Process some CLI arguments.')
+    #     for var in variables:
+    #         if var['cliArgument']['enable']:
+    #             if var['name'] == 'vhelp':
+    #                 parser.add_argument(
+    #                     f"--{var['name']}",
+    #                     var['cliArgument']['short'],
+    #                     required=var['cliArgument']['required'],
+    #                     action='store_true',
+    #                     help=var['cliArgument'].get('description', f'Specify the {var["name"]} variable value - default: "{var["default"]}"')
+    #                 )
+    #             else:
+    #                 parser.add_argument(
+    #                     f"--{var['name']}",
+    #                     var['cliArgument']['short'],
+    #                     required=var['cliArgument']['required'],
+    #                     default=var['default'],
+    #                     help=var['cliArgument'].get('description', f'Specify the {var["name"]} variable value - default: "{var["default"]}"')
+    #                 )
+    #     return parser
+
+    # def build_variables(self, inital_args, variables):
+    #     # Combine default CLI args and dashboard variables
+    #     all_variables = inital_args + variables
+
+    #     # Rebuild the parser with all variables
+    #     final_parser = self.build_parser(all_variables)
+
+    #     # Parse all arguments with the final parser, ignoring unknown args
+    #     final_args, unknown_args = final_parser.parse_known_args()
+    #     rich.print("Parsed arguments:", final_args)
+    #     rich.print("Unknown arguments:", unknown_args)
+
+    #     # Store the arguments in the variables dictionary
+    #     args_dict = vars(final_args)
+    #     if args_dict.get('vhelp'):
+    #         final_parser.print_help()
+    #         return
+
+    #     for arg, value in args_dict.items():
+    #         self.variables[arg] = value
+
+    #     for arg, value in args_dict.items():
+    #         if value == 'ALL':
+    #             value = ".*"
+    #         self.variables[arg] = value
+
+    #     return final_args
+
+    def build_custom_dashboard(self, dashboard_data, dashboard_variables, print_layout=False):
+
+        # Build the Layout structure
+        self.make_layout(layout_structure_dct=dashboard_data['data'], print_layout=print_layout)
+
+        # vistualize the metrics on the layout
+        self.variables = dashboard_variables
+        self.update_layout_visualization(layout_structure_dct=dashboard_data['data'])
+
+
+    def update_layout_visualization(self, layout_structure_dct):
+        visualization_dct = layout_structure_dct['dashboard']['visualization']
+
+        for visualization in visualization_dct:
+            if visualization.get('enable', True):
+                if visualization['type'] == 'asciiGraph':
+                    if 'custom_key' in visualization:
+                        self.build_ascii_graph_handler(name=visualization['name'], layout_box_name=visualization['box'], graph_options=visualization.get('asciiGraphOptions', {}), metric_unit=visualization['metricUnit'], metric=visualization['metric'], custom_key=visualization.get('custom_key', ''))
+                    else:
+                        self.build_ascii_graph_handler(name=visualization['name'], layout_box_name=visualization['box'], graph_options=visualization.get('asciiGraphOptions', {}), metric_unit=visualization['metricUnit'], metric=visualization['metric'])
+
+                elif visualization['type'] == 'progressBarList':
+                    if 'custom_key' in visualization:
+                        self.build_progress_bar_list_handler(name=visualization['name'], layout_box_name=visualization['box'], progress_bar_list_options=visualization.get('progressBarListOptions', {}), metric_unit=visualization['metricUnit'], total_value_metric=visualization['metrics']['total_value_metric'], usage_value_metric=visualization['metrics']['usage_value_metric'], custom_key=visualization['custom_key'])
+                    else:
+                        self.build_progress_bar_list_handler(name=visualization['name'], layout_box_name=visualization['box'], progress_bar_list_options=visualization.get('progressBarListOptions', {}), metric_unit=visualization['metricUnit'], total_value_metric=visualization['metrics']['total_value_metric'], usage_value_metric=visualization['metrics']['usage_value_metric'])
+
+                elif visualization['type'] == 'simpleTable':
+                    self.build_simple_table_handler(name=visualization['name'], layout_box_name=visualization['box'], simple_table_options=visualization.get('simpleTableOptions', {}), metric_unit=visualization.get('metricUnit', 'None'), metric=visualization['metric'])
+
+                elif visualization['type'] == 'advancedTable':
+                    if 'custom_key' in visualization:
+                        self.build_advanced_table_handler(name=visualization['name'], layout_box_name=visualization['box'], advanced_table_options=visualization.get('advancedTableOptions', {}), metric_unit=visualization.get('metricUnit', ''), columns=visualization['advancedTableColumns'], custom_key=visualization.get('custom_key', ''))
+                    else:
+                        self.build_advanced_table_handler(name=visualization['name'], layout_box_name=visualization['box'], advanced_table_options=visualization.get('advancedTableOptions', {}), metric_unit=visualization['metricUnit'], columns=visualization['columns'])
+
+                else:
+                    pass
+        import time
+        import traceback
+        Logging.log.info("Starting the Layout.")
+        try:
+            with Live(self.layout, auto_refresh=True, screen=layout_structure_dct['dashboard']['layout'].get('fullScreen', True), refresh_per_second=GlobalAttrs.live_update_interval):
+                while True:
+                    Logging.log.info(f"waiting for the update interval '{GlobalAttrs.live_update_interval}' before updating the Layout ")
+                    time.sleep(GlobalAttrs.live_update_interval)
+                    Logging.log.info(f"Updating the layout")
+
+        except Exception as e:
+            rich.print("\n[yellow]ERROR -- " + str(e))
+            rich.print("\n[underline bold]Exception:")
+            traceback.print_exc()
+            exit(1)
+        except KeyboardInterrupt:
+            print("                 ", end="\r")
+            rich.print("Ok")
+            exit(0)
+
+    def parse_dashboard_yaml_file(self, yaml_file):
+        out = {
+            "success": False,
+            "data": None,
+            "fail_reason": ""
+        }
+
+        # Check if the file does NOT exist
+        if not os.path.isfile(yaml_file):
+            out['fail_reason'] = f"Dashboard File '{yaml_file}' does NOT exist"
+            return out
+
+        # Read the file
+        try:
+            with open(yaml_file, 'r') as file:
+                content = file.read()
+                out['data'] = yaml.safe_load(content)
+        except Exception as e:
+            out['fail_reason'] = f"Failed to open the dashboard file '{yaml_file}' > {e}"
+            return out
+
+        out['success'] = True
+        return out
+
+
+    def validate_dashboard_yaml(self, yaml_file):
+        pass
+
+    def make_layout(self, layout_structure_dct, print_layout=False) -> Layout:
+        """
+        Build a custom layout structure
+        """
+        layout_dct = layout_structure_dct['dashboard']['layout']
+        layout = Layout(name="root")
+
+        if layout_dct['header']['enable']:
+            layout.split(
+                Layout(name="header", size=3, ratio=1),
+                Layout(name="main", ratio=1),
+            )
+        else:
+            layout.split(
+                Layout(name="main", ratio=1),
+            )
+
+        layout["main"].split_row(
+            Layout(name="body", ratio=3, minimum_size=100,),
+        )
+
+        left_enable = layout_dct['body']['boxes'].get('left', {}).get('enable', False)
+        right_enable = layout_dct['body']['boxes'].get('right', {}).get('enable', False)
+        middle_enable = layout_dct['body']['boxes'].get('middle', {}).get('enable', False)
+        split_mode = layout_dct.get('split_mode', 'row')
+
+        # If all are enabled
+        if left_enable and right_enable and middle_enable:
+            if split_mode == 'row':
+                layout["body"].split_row(
+                    Layout(name="left", size=layout_dct['body']['boxes']['left']['size']),
+                    Layout(name="middle", size=layout_dct['body']['boxes']['middle']['size']),
+                    Layout(name="right", size=layout_dct['body']['boxes']['right']['size'])
+                )
+            elif split_mode == 'column':
+                layout["body"].split_column(
+                    Layout(name="left", size=layout_dct['body']['boxes']['left']['size']),
+                    Layout(name="middle", size=layout_dct['body']['boxes']['middle']['size']),
+                    Layout(name="right", size=layout_dct['body']['boxes']['right']['size'])
+                )
+            self.layout_list = ['left', 'middle', 'right']
+
+        # If two are enabled
+        elif left_enable and right_enable:
+            if split_mode == 'row':
+                layout["body"].split_row(
+                    Layout(name="left", size=layout_dct['body']['boxes']['left']['size']),
+                    Layout(name="right", size=layout_dct['body']['boxes']['right']['size'])
+                )
+            elif split_mode == 'column':
+                layout["body"].split_column(
+                    Layout(name="left", size=layout_dct['body']['boxes']['left']['size']),
+                    Layout(name="right", size=layout_dct['body']['boxes']['right']['size'])
+                )
+            self.layout_list = ['left', 'right']
+
+        elif left_enable and middle_enable:
+            if split_mode == 'row':
+                layout["body"].split_row(
+                    Layout(name="left", size=layout_dct['body']['boxes']['left']['size']),
+                    Layout(name="middle", size=layout_dct['body']['boxes']['middle']['size'])
+                )
+            elif split_mode == 'column':
+                layout["body"].split_column(
+                    Layout(name="left", size=layout_dct['body']['boxes']['left']['size']),
+                    Layout(name="middle", size=layout_dct['body']['boxes']['middle']['size'])
+                )
+            self.layout_list = ['left', 'middle']
+
+        elif right_enable and middle_enable:
+            if split_mode == 'row':
+                layout["body"].split_row(
+                    Layout(name="middle", size=layout_dct['body']['boxes']['middle']['size']),
+                    Layout(name="right", size=layout_dct['body']['boxes']['right']['size'])
+                )
+                self.layout_list = ['middle', 'right']
+            elif split_mode == 'column':
+                layout["body"].split_column(
+                    Layout(name="middle", size=layout_dct['body']['boxes']['middle']['size']),
+                    Layout(name="right", size=layout_dct['body']['boxes']['right']['size'])
+                )
+                self.layout_list = ['middle', 'right']
+
+        # If one is enabled
+        elif left_enable:
+            layout["body"].split_row(
+                Layout(name="left", size=layout_dct['body']['boxes']['left']['size'])
+            )
+            self.layout_list = ['left']
+
+        elif right_enable:
+            layout["body"].split_row(
+                Layout(name="right", size=layout_dct['body']['boxes']['right']['size'])
+            )
+            self.layout_list = ['right']
+
+        elif middle_enable:
+            layout["body"].split_row(
+                Layout(name="middle", size=layout_dct['body']['boxes']['middle']['size'])
+            )
+            self.layout_list = ['middle']
+
+        # If nothing is enabled
+        else:
+            self.layout_list = []
+
+        if right_enable:
+            if layout_dct['body']['boxes']['right'].get('split', {}):
+                layout_objects =  []
+                for box_name, box_info in layout_dct['body']['boxes']['right']['split'].items():
+                    layout_objects.append(Layout(name=box_name, size=box_info['size'], ratio=box_info['ratio']))
+                    self.layout_list.append(box_name)
+
+                if layout_dct['body']['boxes']['right']['split_mode'] == "column":
+                    layout['right'].split_column(*layout_objects)
+                if layout_dct['body']['boxes']['right']['split_mode'] == "row":
+                    layout['right'].split_row(*layout_objects)
+
+        if left_enable:
+            if layout_dct['body']['boxes']['left'].get('split', {}):
+                layout_objects =  []
+                for box_name, box_info in layout_dct['body']['boxes']['left']['split'].items():
+                    layout_objects.append(Layout(name=box_name, size=box_info['size'], ratio=box_info['ratio']))
+                    self.layout_list.append(box_name)
+
+                if layout_dct['body']['boxes']['left']['split_mode'] == "column":
+                    layout['left'].split_column(*layout_objects)
+                if layout_dct['body']['boxes']['left']['split_mode'] == "row":
+                    layout['left'].split_row(*layout_objects)
+
+        if middle_enable:
+            if layout_dct['body']['boxes']['middle'].get('split', {}):
+                layout_objects =  []
+                for box_name, box_info in layout_dct['body']['boxes']['middle']['split'].items():
+                    layout_objects.append(Layout(name=box_name, size=box_info['size'], ratio=box_info['ratio']))
+                    self.layout_list.append(box_name)
+
+                if layout_dct['body']['boxes']['middle']['split_mode'] == "column":
+                    layout['middle'].split_column(*layout_objects)
+                if layout_dct['body']['boxes']['middle']['split_mode'] == "row":
+                    layout['middle'].split_row(*layout_objects)
+
+        if print_layout:
+            # rich.print_json(json.dumps(layout_dct, indent=4))
+            rich.print(layout)
+            exit(0)
+
+        self.layout = layout
+        return layout
+
+    # def convert_data_unit(self, value, metric_unit):
+    #     if metric_unit == 'byte':
+    #         value = helper_.bytes_to_kb_mb_gb(value)
+    #     elif metric_unit == 'seconds':
+    #         value =  helper_.seconds_to_human_readable(value)
+    #     elif metric_unit == 'milliseconds':
+    #         value =  helper_.milliseconds_to_human_readable(value)
+    #     elif metric_unit == 'timestamp':
+    #         value =  helper_.convert_epoch_timestamp(value)
+    #     return value
+
+    def safe_eval(self, custom_key, labels):
+        for key, value in labels.items():
+            custom_key = custom_key.replace(f"{{{{{key}}}}}", f"{value}")
+        return custom_key
+
+    def get_metric_data(self, metric, custom_key=None, evaluate_cli_argument_variables=False, value_from_label=""):
+        out = {
+            "success": False,
+            "data": None,
+            "fail_reason": "",
+            "metric": ""
+        }
+
+        # Replace variables
+        metric = self.replace_cli_argument_variable(metric)
+        out['metric'] = metric
+        # Run Metric
+        metric_result = self.run_query(metric)
+
+        if not metric_result.get('status') == 'success':
+            out['fail_reason'] = "could not get metric value (Possible Syntax Error)"
+            return out
+
+        if not metric_result.get('data').get('result'):
+            out['fail_reason'] = "metric did not return any data"
+            return out
+
+        dct = {}
+        for i in metric_result['data']['result']:
+            labels = i['metric']
+
+            key = ""
+            if custom_key:
+                try:
+                    # key = str(eval(custom_key))
+                    key = helper_.safe_eval(custom_key, labels)
+                except KeyError as e:
+                    out['fail_reason'] = f"Label NOT found {e} --> Query: {metric}"
+                    # key = f"Label NOT found: {e}"
+                    # key = str(eval(custom_key.replace(e, 'not_found')))
+                except SyntaxError as e:
+                    out['fail_reason'] = f"Python Syntax Error: {e} --> {custom_key}"
+                    key = "Python Syntax Error"
+
+                except Exception as e:
+                    out['fail_reason'] = f"failed to replace the key with custom_key: {e}"
+                    key = str(e)
+
+            else:
+                key = str(i['metric'])
+
+            if value_from_label:
+                dct[key] = {
+                    "timestamp":i['value'][0],
+                    "value":i['metric'].get(value_from_label, 'label_not_found'),
+                }
+            else:
+                dct[key] = {
+                    "timestamp":i['value'][0],
+                    "value":i['value'][1]
+                }
+        out['data'] = dct
+        out['success'] = True
+        return out
+
+    def _find_variables_in_query(self, query):
+        # Find all variables in the form $VARIABLE
+        variables = re.findall(r'\$\w+', query)
+        return variables
+
+    def replace_cli_argument_variable(self, query):
+        out = {
+            "success": False,
+            "data": None,
+            "fail_reason": ""
+        }
+        found_variables = self._find_variables_in_query(query)
+        if found_variables:
+            for variable in found_variables:
+                if variable[1:] in self.variables:
+                    # Replace the variable in the query string
+                    query = query.replace(variable, self.variables[variable[1:]])
+        return query
+
+    def build_ascii_graph_handler(self, name, layout_box_name, graph_options, metric_unit, metric, custom_key=None):
+        # Print loading message
+        try:
+            self.layout[layout_box_name].update(Panel(GlobalAttrs.initial_message, title=f"[b]{name}", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+        except KeyError as e:
+            logging.error(e)
+            print(f"ERROR -- while starting '{name}' box" + str(e))
+            exit(1)
+        # Start thread
+        thread = threading.Thread(target=self.build_ascii_graph, args=(name, layout_box_name, graph_options, metric_unit, metric, custom_key))
+        thread.name = name
+        self.threads[name] = thread
+        thread.daemon = True
+        thread.start()
+
+    def build_ascii_graph(self, name, layout_box_name, graph_options, metric_unit, metric, custom_key=None):
+        graph = None
+        while True:
+            metric_data_dct = self.get_metric_data(metric=metric, custom_key=custom_key)
+
+            if not metric_data_dct['success']:
+                self.layout[layout_box_name].update(Panel(f"[red]Failed to get data from query 'total_value_metric': [bold]{metric_data_dct['fail_reason']}[/bold][/red]\n\n[bold]METRIC:[/bold]\n[grey53]{metric_data_dct['metric']}", title=f"[b]{name}", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+
+            data_graph = AsciiGraph()
+
+            if graph_options:
+                height_ = graph_options.get("height", 0)
+                width_ = graph_options.get("width", 0)
+                max_height_ = graph_options.get("maxHeight", 20)
+                max_width_ = graph_options.get("maxWidth", 20)
+                update_interval_ = graph_options.get("updateIntervalSeconds", 5)
+            else:
+                height_ = 17
+                width_ = 45
+                max_height_ = 20
+                max_width_ = 50
+                update_interval_ = 5
+
+            # Save the graph object
+            if not graph:
+                data_graph.create_graph(names=list(metric_data_dct['data'].keys()), height=height_, width=width_, max_height=max_height_, max_width=max_width_, format=f'{{:8.0f}} {metric_unit}')
+                graph = data_graph
+
+            # Update the grap data
+            for k, v in metric_data_dct['data'].items():
+                graph.update_lst(k, float(v['value']), format=f'{{:8.0f}} {metric_unit}')
+
+            # Organize the graph lines & items visualization
+            data_group = Group(
+                Text.from_ansi(graph.graph),
+                Rule(style='#AAAAAA'),
+                # Markdown("Bytes Written", justify='center'),
+                Text.from_ansi(graph.colors_description_str)
+            )
+
+            self.layout[layout_box_name].update(Panel(data_group, title=f"[b]{name}", subtitle=f"Thread: {helper_.check_thread_status(self.threads[name])}", subtitle_align="left", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+            time.sleep(update_interval_)
+
+
+    def build_progress_bar_list_handler(self, name, layout_box_name, progress_bar_list_options, metric_unit, total_value_metric, usage_value_metric, custom_key=None):
+        # Print loading message
+        self.layout[layout_box_name].update(Panel(GlobalAttrs.initial_message, title=f"[b]{name}", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+        # Start thread
+        thread = threading.Thread(target=self.build_progress_bar_list, args=(name, layout_box_name, progress_bar_list_options, metric_unit, total_value_metric, usage_value_metric, custom_key))
+        thread.name = name
+        self.threads[name] = thread
+        thread.daemon = True
+        thread.start()
+
+    def build_progress_bar_list(self, name, layout_box_name, progress_bar_list_options, metric_unit, total_value_metric, usage_value_metric, custom_key=None):
+
+        while True:
+            # Get usage data
+            total_data = self.get_metric_data(total_value_metric, custom_key=custom_key)
+            if not total_data['success']:
+                self.layout[layout_box_name].update(Panel(f"[red]Failed to get data from query 'total_value_metric': [bold]{total_data['fail_reason']}[/bold][/red]\n\n[bold]METRIC:[/bold]\n[grey53]{total_data['metric']}", title=f"[b]{name}", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+
+            usage_data = self.get_metric_data(usage_value_metric, custom_key=custom_key)
+            if not usage_data['success']:
+                self.layout[layout_box_name].update(Panel(f"[red]Failed to get data from query 'total_value_metric': [bold]{total_data['fail_reason']}[/bold][/red]\n\n[bold]METRIC:[/bold]\n[grey53]{total_data['metric']}", title=f"[b]{name}", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+
+            data = {}
+            for k, v in usage_data['data'].items():
+                try:
+                    data[k] = {
+                        "value": v['value'],
+                        "total": total_data['data'][k].get('value')
+                    }
+                except KeyError as e:
+                    pass
+
+            if progress_bar_list_options:
+                max_items_list = progress_bar_list_options.get('maxItemsCount', 20)
+                line_break = progress_bar_list_options.get('lineBreak', True)
+                show_bar_percentage = progress_bar_list_options.get('showBarPercentage', True)
+                bar_width = progress_bar_list_options.get('barWidth', 20)
+                bar_width = progress_bar_list_options.get('barWidth', 20)
+                update_interval_ = progress_bar_list_options.get("updateIntervalSeconds", 5)
+
+            else:
+                max_items_list = 20
+                line_break = True
+                show_bar_percentage = True
+                bar_width = 20
+                update_interval_ = 5
+
+            progress_bars = []
+            for progress_bar_name, progress_bar_data in islice(data.items(), max_items_list):
+                if show_bar_percentage:
+                    progress_bar = Progress(
+                        TextColumn("[progress.description]{task.description}"),
+                        BarColumn(bar_width=bar_width),
+                        # TaskProgressColumn(),
+                        TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
+                        TextColumn("{task.fields[status]}"),
+                    )
+                else:
+                    progress_bar = Progress(
+                        TextColumn("[progress.description]{task.description}"),
+                        BarColumn(bar_width=bar_width),
+                        TextColumn("{task.fields[status]}"),
+                    )
+
+                task_mem_total = progress_bar.add_task(description=f"[white]Mem Total  ", status="Loading", total=float(data[progress_bar_name]['total']))
+                progress_bar.update(task_mem_total, completed=float(data[progress_bar_name]['value']), total=float(data[progress_bar_name]['total']), description=f"[white]{progress_bar_name}  ", status=f"  {helper_.bytes_to_kb_mb_gb(float(data[progress_bar_name]['value']))} / {helper_.bytes_to_kb_mb_gb(float(data[progress_bar_name]['total']))}")
+                progress_bars.append(progress_bar)
+                if line_break:
+                    progress_bars.append(Rule(style='#AAAAAA'))
+
+
+            data_group = Group(
+                *progress_bars,
+            )
+
+            # return data_group
+            self.layout[layout_box_name].update(Panel(data_group, title=f"[b]{name}", subtitle=f"Thread: {helper_.check_thread_status(self.threads[name])}", subtitle_align="left", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+            time.sleep(update_interval_)
+
+    def build_simple_table_handler(self, name, layout_box_name, simple_table_options, metric_unit, metric, custom_key=None):
+        # Print loading message
+        self.layout[layout_box_name].update(Panel(GlobalAttrs.initial_message, title=f"[b]{name}", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+        # Start thread
+        thread = threading.Thread(target=self.build_simple_table, args=(name, layout_box_name, simple_table_options, metric_unit, metric))
+        thread.name = name
+        self.threads[name] = thread
+        thread.daemon = True
+        thread.start()
+
+
+    def build_simple_table(self, name, layout_box_name, simple_table_options, metric_unit, metric, custom_key=None):
+
+        if simple_table_options:
+            table_type_ = simple_table_options.get("tableType", 'plain')
+            show_value_ = simple_table_options.get("showValue", True)
+            header_upper_case_ = simple_table_options.get("headersUppercase", True)
+            auto_convert_value_ = simple_table_options.get("autoConvertValue", True)
+            show_table_index_ = simple_table_options.get("showTableIndex", True)
+            update_interval_ = simple_table_options.get("updateIntervalSeconds", 5)
+        else:
+            table_type_ = 'plain'
+            show_value_ = True
+            header_upper_case_ = True
+            auto_convert_value_ = True
+            show_table_index_ = True
+            update_interval_ = 5
+
+        while True:
+            # Get metric data
+            metric_data_dct = self.get_metric_data(metric, custom_key=custom_key)
+            if not metric_data_dct['success']:
+                self.layout[layout_box_name].update(Panel(f"[red]Failed to get data from query 'total_value_metric': [bold]{metric_data_dct['fail_reason']}[/bold][/red]\n\n[bold]METRIC:[/bold]\n[grey53]{metric_data_dct['metric']}", title=f"[b]{name}", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+
+            first_dict_item = next(iter(metric_data_dct['data'].items()))[0]
+            dict_keys = list(ast.literal_eval(first_dict_item).keys())
+
+            if show_value_:
+                dict_keys.append('values')
+
+            if header_upper_case_:
+                dict_keys = [key.upper() for key in dict_keys]
+
+
+            table = [dict_keys]
+            data = {}
+            for labels, value in metric_data_dct['data'].items():
+                labels_dct = ast.literal_eval(labels)
+                row_list = list(labels_dct.values())
+                if show_value_:
+                    value_ = int(float(value['value']))
+                    if auto_convert_value_:
+                        if metric_unit == 'byte':
+                            value_ = helper_.bytes_to_kb_mb_gb(value_)
+                        elif metric_unit == 'cpu_seconds':
+                            value_ = value_
+                    row_list.append(value_)
+                row = row_list
+                table.append(row)
+
+
+            out = tabulate(table, headers='firstrow', tablefmt=table_type_, showindex=show_table_index_)
+            data_group = Group(
+                out,
+            )
+            # return data_group
+            self.layout[layout_box_name].update(Panel(data_group, title=f"[b]{name}", subtitle=f"Thread: {helper_.check_thread_status(self.threads[name])}", subtitle_align="left", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+            time.sleep(update_interval_)
+
+
+    def build_advanced_table_handler(self, name, layout_box_name, advanced_table_options, metric_unit, columns, custom_key=None):
+        # Print loading message
+        self.layout[layout_box_name].update(Panel(GlobalAttrs.initial_message, title=f"[b]{name}", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+        # Start thread
+        thread = threading.Thread(target=self.build_advanced_table, args=(name, layout_box_name, advanced_table_options, metric_unit, columns, custom_key))
+        thread.name = name
+        thread.daemon = True
+        self.threads[name] = thread
+        thread.start()
+
+    def build_advanced_table(self, name, layout_box_name, advanced_table_options, metric_unit, columns, custom_key=None):
+
+        if advanced_table_options:
+            table_type_ = advanced_table_options.get("tableType", 'plain')
+            # show_value_ = advanced_table_options.get("showValue", True)
+            header_upper_case_ = advanced_table_options.get("headersUppercase", True)
+            show_table_index_ = advanced_table_options.get("showTableIndex", True)
+            update_interval_ = advanced_table_options.get("updateIntervalSeconds", 5)
+        else:
+            table_type_ = 'plain'
+            # show_value_ = True
+            header_upper_case_ = True
+            show_table_index_ = True
+            update_interval_ = 5
+
+        box_name = name
+        data = {}
+
+        columns_dct = {}
+        for column in columns:
+            key = next(iter(column))
+            new_dct = {k: v for k, v in column.items() if k != key}
+            columns_dct[key] = new_dct
+
+        header = list(columns_dct.keys())
+        header.insert(0, 'name')
+
+        if header_upper_case_:
+            header = [key.upper() for key in header]
+
+        while True:
+            table = [header]
+            for column, column_info in columns_dct.items():
+                auto_convert_value_ = column_info.get('autoConvertValue', False)
+                metric_data = self.get_metric_data(column_info['metric'], custom_key=custom_key, value_from_label=column_info.get('valueFromLabel', ''))
+
+                if not metric_data['success']:
+                    self.layout[layout_box_name].update(Panel(f"[red]Failed to get data from query 'total_value_metric': [bold]{metric_data['fail_reason']}[/bold][/red]\n\n[bold]METRIC:[/bold]\n[grey53]{metric_data['metric']}", title=f"[b]{name}", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+
+                for name, value in metric_data['data'].items():
+                    try:
+                        value_ = float(value['value'])
+                        if auto_convert_value_:
+                            value_ = helper_.convert_data_unit(value=value_, metric_unit=column_info['metricUnit'])
+                    except:
+                        value_ = value['value']
+
+                    try:
+                        data[name][column] = value_
+                    except KeyError:
+                        data[name] = {
+                            column: value_
+                        }
+
+            for name, value in data.items():
+                row = [name] + [value.get(col, '?') for col in columns_dct.keys()]  # Ensure order matches headers
+                table.append(row)
+
+            out = tabulate(table, headers='firstrow', tablefmt=table_type_, showindex=show_table_index_)
+            data_group = Group(
+                out
+            )
+            self.layout[layout_box_name].update(Panel(data_group, title=f"[b]{box_name}", subtitle=f"Thread: {helper_.check_thread_status(self.threads[box_name])}", subtitle_align="left", padding=(1, 1), expand=True, safe_box=True, highlight=True, height=0))
+            time.sleep(update_interval_)
diff --git a/kubePtop/dashboard_yaml_loader.py b/kubePtop/dashboard_yaml_loader.py
new file mode 100644
index 0000000..fd089c5
--- /dev/null
+++ b/kubePtop/dashboard_yaml_loader.py
@@ -0,0 +1,593 @@
+import os
+import yaml
+import json
+from cerberus import Validator
+import rich
+class dashboardYamlLoader:
+    def __init__(self) -> None:
+        self.allowed_metric_unit_types = [
+            'None',
+            'kb',
+            'byte',
+            'mb',
+            'gb',
+            'tb',
+            'seconds',
+            'percentage'
+        ]
+
+    def validate_dashboard_schema(self, dashboard_yaml_data):
+        schema_dct = {
+
+            "dashboard": {
+                'type': 'dict',
+                'required': True,
+                'schema': {
+                    "name": {
+                        'type': 'string',
+                        'required': True,
+                    },
+                    "description": {
+                        'type': 'string',
+                        'required': False,
+                        'default': ""
+                    },
+                    "layout": {
+                        'type': 'dict',
+                        'required': True,
+                        'schema': {
+                            'splitMode': {
+                                "type": "string",
+                                'required': False,
+                                'default': 'row',
+                                'allowed': [
+                                    'row',
+                                    'column'
+                                ]
+                            },
+                            'fullScreen': {
+                                "type": "boolean",
+                                'required': False,
+                                'default': True,
+                                'allowed': [
+                                    True,
+                                    False
+                                ]
+                            },
+                            "header": {
+                                'type': 'dict',
+                                'required': False,
+                                'schema': {
+                                    'enable': {
+                                        "type": "boolean",
+                                        'required': False,
+                                        'default': False
+                                    },
+                                    'size': {
+                                        "type": "integer",
+                                        'required': False,
+                                        'default': 0
+                                    },
+                                    'ratio': {
+                                        "type": "integer",
+                                        'required': True,
+                                        'default': 1
+                                    },
+                                }
+                            },
+                            'body': {
+                                    'type': 'dict',
+                                    'schema': {
+                                        'boxes': {
+                                            'type': 'dict',
+                                            'schema': {
+                                                'left': {
+                                                    'type': 'dict',
+                                                    'required': True,
+                                                    'schema': {
+                                                        'enable': {
+                                                            'type': 'boolean',
+                                                            'required': False,
+                                                            'default': False,
+                                                        },
+                                                        'size': {
+                                                            'type': 'integer',
+                                                            'required': False,
+                                                            'default': 0
+                                                        },
+                                                        'ratio': {
+                                                            'type': 'integer',
+                                                            'required': False,
+                                                            'default': 1
+                                                        },
+                                                        'split_mode': {
+                                                            'type': 'string',
+                                                            'required': False,
+                                                            'default': 'row',
+                                                            'allowed': [
+                                                                'row',
+                                                                'column'
+                                                            ]
+                                                        },
+                                                        'split': {
+                                                            'type': 'dict',
+                                                            'required': False,
+                                                            'allow_unknown': True,
+                                                            'schema': {
+                                                                'size': {
+                                                                    'type': 'integer',
+                                                                    'required': False,
+                                                                    'default': 0
+                                                                },
+                                                                'ratio': {
+                                                                    'type': 'integer',
+                                                                    'required': False,
+                                                                    'default': 1
+                                                                }
+                                                            }
+                                                        }
+                                                    }
+                                                },
+                                                'middle': {
+                                                    'type': 'dict',
+                                                    'required': True,
+                                                    'schema': {
+                                                        'enable': {
+                                                            'type': 'boolean',
+                                                            'required': False,
+                                                            'default': False
+                                                        },
+                                                        'size': {
+                                                            'type': 'integer',
+                                                            'required': False,
+                                                            'default': 0
+                                                        },
+                                                        'ratio': {
+                                                            'type': 'integer',
+                                                            'required': False,
+                                                            'default': 1
+                                                        },
+                                                        'split_mode': {
+                                                            'type': 'string',
+                                                            'required': False,
+                                                            'default': 'row',
+                                                            'allowed': [
+                                                                'row',
+                                                                'column'
+                                                            ]
+                                                        },
+                                                        'split': {
+                                                            'type': 'dict',
+                                                            'required': False,
+                                                            'allow_unknown': True,
+                                                            'schema': {
+                                                                'size': {
+                                                                    'type': 'integer',
+                                                                    'required': False,
+                                                                    'default': 0
+                                                                },
+                                                                'ratio': {
+                                                                    'type': 'integer',
+                                                                    'required': False,
+                                                                    'default': 1
+                                                                }
+                                                            }
+                                                        }
+                                                    }
+                                                },
+                                                'right': {
+                                                    'type': 'dict',
+                                                    'required': True,
+                                                    'schema': {
+                                                        'enable': {
+                                                            'type': 'boolean',
+                                                            'required': False,
+                                                            'default': False,
+                                                        },
+                                                        'size': {
+                                                            'type': 'integer',
+                                                            'required': False,
+                                                            'default': 0
+                                                        },
+                                                        'ratio': {
+                                                            'type': 'integer',
+                                                            'required': False,
+                                                            'default': 1
+                                                        },
+                                                        'split_mode': {
+                                                            'type': 'string',
+                                                            'required': False,
+                                                            'default': 'row',
+                                                            'allowed': [
+                                                                'row',
+                                                                'column'
+                                                            ]
+                                                        },
+                                                        'split': {
+                                                            'type': 'dict',
+                                                            'required': False,
+                                                            'allow_unknown': True,
+                                                            'schema': {
+                                                                'size': {
+                                                                    'type': 'integer',
+                                                                    'required': False,
+                                                                    'default': 0
+                                                                },
+                                                                'ratio': {
+                                                                    'type': 'integer',
+                                                                    'required': False,
+                                                                    'default': 1
+                                                                }
+                                                            }
+                                                        }
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                },
+                        }
+                    },
+                    'variables': {
+                        'type': 'list',
+                        'schema': {
+                            'type': 'dict',
+                            'schema': {
+                                'name': {
+                                    'type': 'string',
+                                    'required': True
+                                },
+                                'default': {
+                                    'type': 'string',
+                                    'required': True,
+                                },
+                                'cliArgument': {
+                                    'type': 'dict',
+                                    'schema': {
+                                        'enable': {
+                                            'type': 'boolean',
+                                            'required': True
+                                        },
+                                        'short': {
+                                            'type': 'string',
+                                            'required': True,
+                                            'regex': r'^-\w{1,2}$'
+                                        },
+                                        'required': {
+                                            'type': 'boolean',
+                                            'default': True,
+                                            'required': False
+                                        },
+                                        'description': {
+                                            'type': 'string',
+                                            'required': False
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    'visualization': {
+                            'type': 'list',
+                            'schema': {
+                                'type': 'dict',
+                                'allow_unknown': True,
+                                'schema': {
+                                    'name': {
+                                        'type': 'string',
+                                        'required': True
+                                    },
+                                    'box': {
+                                        'type': 'string',
+                                        'required': True
+                                    },
+                                    'enable': {
+                                        'type': 'boolean',
+                                        'required': False,
+                                        'default': True
+                                    },
+                                    'type': {
+                                        'type': 'string',
+                                        'required': True,
+                                        'allowed': [
+                                            'asciiGraph',
+                                            'progressBarList',
+                                            'simpleTable',
+                                            'advancedTable',
+                                        ]
+                                    },
+                                    'metricUnit': {
+                                        'type': 'string',
+                                        'required': False,
+                                        'default': 'None',
+                                        'allowed': self.allowed_metric_unit_types
+                                    },
+                                    'metric': {
+                                        'type': 'string'
+                                    },
+                                    'custom_key': {
+                                        'type': 'string',
+                                        'default': '',
+                                        'required': False,
+                                    },
+                                    'asciiGraphOptions': {
+                                        'type': 'dict',
+                                        'schema': {
+                                            'height': {
+                                                'type': 'integer',
+                                                'required': False,
+                                                'default': 0,
+                                            },
+                                            'width': {
+                                                'type': 'integer',
+                                                'required': False,
+                                                'default': 80,
+                                            },
+                                            'maxHeight': {
+                                                'type': 'integer',
+                                                'required': False,
+                                                'default': 17,
+                                            },
+                                            'maxWidth': {
+                                                'type': 'integer',
+                                                'required': False,
+                                                'default': 45,
+                                            },
+                                            'updateIntervalSeconds': {
+                                                'type': 'integer',
+                                                'required': False,
+                                                'default': 5,
+                                            }
+                                        }
+                                    },
+                                    'progressBarListOptions': {
+                                        'type': 'dict',
+                                        'schema': {
+                                            'maxItemsCount': {
+                                                'type': 'integer',
+                                                'required': False,
+                                                'default': 0,
+                                            },
+                                            'lineBreak': {
+                                                'type': 'boolean',
+                                                'required': False,
+                                                'default': True,
+                                            },
+                                            'showBarPercentage': {
+                                                'type': 'boolean',
+                                                'required': False,
+                                                'default': True,
+                                            },
+                                            'barWidth': {
+                                                'type': 'integer',
+                                                'required': False,
+                                                'default': 25,
+                                            },
+                                            'updateIntervalSeconds': {
+                                                'type': 'integer',
+                                                'required': False,
+                                                'default': 5,
+                                            }
+                                        }
+                                    },
+                                    'simpleTableOptions': {
+                                        'type': 'dict',
+                                        'schema': {
+                                            'tableType': {
+                                                'type': 'string',
+                                                'required': False,
+                                                'default': 'plain',
+                                                'allowed': [
+                                                    'plain',
+                                                    'simple',
+                                                    'github',
+                                                    'grid',
+                                                    'simple_grid',
+                                                    'rounded_grid',
+                                                    'heavy_grid',
+                                                    'mixed_grid',
+                                                    'double_grid',
+                                                    'fancy_grid',
+                                                    'outline',
+                                                    'simple_outline',
+                                                    'rounded_outline',
+                                                    'heavy_outline',
+                                                    'mixed_outline',
+                                                    'double_outline',
+                                                    'fancy_outline',
+                                                    'pipe',
+                                                    'orgtbl',
+                                                    'asciidoc',
+                                                    'jira',
+                                                    'presto',
+                                                    'pretty',
+                                                    'psql',
+                                                    'rst',
+                                                    'mediawiki',
+                                                    'moinmoin',
+                                                    'youtrack',
+                                                    'html',
+                                                    'unsafehtml',
+                                                    'latex',
+                                                    'latex_raw',
+                                                    'latex_booktabs',
+                                                    'latex_longtable',
+                                                    'textile',
+                                                    'tsv',
+                                                ]
+                                            },
+                                            'showValue': {
+                                                'type': 'boolean',
+                                                'required': True,
+                                                'default': True,
+                                            },
+                                            'headersUppercase': {
+                                                'type': 'boolean',
+                                                'required': True,
+                                                'default': True,
+                                            },
+                                            'autoConvertValue': {
+                                                'type': 'boolean',
+                                                'required': True,
+                                                'default': False,
+                                            },
+                                            'showTableIndex': {
+                                                'type': 'boolean',
+                                                'required': True,
+                                                'default': False,
+                                            },
+                                            'updateIntervalSeconds': {
+                                                'type': 'integer',
+                                                'required': True,
+                                                'default': 5,
+                                            }
+                                        }
+                                    },
+                                    'advancedTableColumns': {
+                                        'type': 'list',
+                                        'required': False,
+                                        'schema': {
+                                            'type': 'dict',
+                                            'required': True,
+                                            'allow_unknown': True,
+                                            'schema': {
+                                                'metric': {
+                                                    'type': 'string',
+                                                    'required': True
+                                                },
+                                                'metricUnit': {
+                                                    'type': 'string',
+                                                    'required': False,
+                                                    'default': 'None',
+                                                    'allowed': self.allowed_metric_unit_types
+                                                },
+                                                'valueFromLabel': {
+                                                    'type': 'string',
+                                                    'required': False,
+                                                    'default': "",
+                                                }
+                                            }
+                                        }
+                                    },
+                                    'advancedTableOptions': {
+                                        'type': 'dict',
+                                        'allow_unknown': False,
+                                        'schema': {
+                                            'tableType': {
+                                                'type': 'string',
+                                                'required': False,
+                                                'default': 'plain',
+                                                'allowed': [
+                                                    'plain',
+                                                    'simple',
+                                                    'github',
+                                                    'grid',
+                                                    'simple_grid',
+                                                    'rounded_grid',
+                                                    'heavy_grid',
+                                                    'mixed_grid',
+                                                    'double_grid',
+                                                    'fancy_grid',
+                                                    'outline',
+                                                    'simple_outline',
+                                                    'rounded_outline',
+                                                    'heavy_outline',
+                                                    'mixed_outline',
+                                                    'double_outline',
+                                                    'fancy_outline',
+                                                    'pipe',
+                                                    'orgtbl',
+                                                    'asciidoc',
+                                                    'jira',
+                                                    'presto',
+                                                    'pretty',
+                                                    'psql',
+                                                    'rst',
+                                                    'mediawiki',
+                                                    'moinmoin',
+                                                    'youtrack',
+                                                    'html',
+                                                    'unsafehtml',
+                                                    'latex',
+                                                    'latex_raw',
+                                                    'latex_booktabs',
+                                                    'latex_longtable',
+                                                    'textile',
+                                                    'tsv',
+                                                ]
+                                            },
+                                            'headersUppercase': {
+                                                'type': 'boolean',
+                                                'required': True,
+                                                'default': True,
+                                            },
+                                            'showTableIndex': {
+                                                'type': 'boolean',
+                                                'required': True,
+                                                'default': False,
+                                            },
+                                            'updateIntervalSeconds': {
+                                                'type': 'integer',
+                                                'required': True,
+                                                'default': 5,
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                }
+            },
+        }
+
+        v = Validator(schema_dct)
+        v.validate(dashboard_yaml_data)
+        if v.errors:
+            import re
+            yaml_errors = yaml.dump(v.errors, default_flow_style=False)
+
+            # Regex to find "unknown field" and "must be of"
+            yaml_errors = re.sub(r'(unknown field)', '[red]\\1[/red]', yaml_errors)
+            yaml_errors = re.sub(r'(must be of.*)', '[red]\\1[/red]', yaml_errors)
+            yaml_errors = re.sub(r'(unallowed value.*)', '[red]\\1[/red]', yaml_errors)
+            yaml_errors = re.sub(r'(required field.*)', '[red]\\1[/red]', yaml_errors)
+            yaml_errors = re.sub(r'(null value not allowe.*)', '[red]\\1[/red]', yaml_errors)
+
+            print("ERROR -- Please fix the following in the dashboard YAML file:\n")
+            rich.print("[bold]" + yaml_errors)
+            exit(1)
+
+
+    def load_dashboard_data(self, command_content_content):
+        out = {
+            "success": False,
+            "data": None,
+            "fail_reason": ""
+        }
+
+
+
+        # Check if the yaml file exists in the dashboards directory
+        ## If so, return the file path
+        ### The dashboard dir is taken as ENV
+        # yaml_file = dashboard_name
+        # # Check if the file does NOT exist
+        # if not os.path.isfile(yaml_file):
+        #     out['fail_reason'] = f"Dashboard File '{yaml_file}' does NOT exist"
+        #     return out
+
+        # Read the file
+        try:
+            # with open(yaml_file, 'r') as file:
+                # content = file.read()
+            out['data'] = yaml.safe_load(command_content_content)
+        except Exception as e:
+            out['fail_reason'] = f"Failed to open the dashboard file content > {e}"
+            return out
+
+        # Yaml Schema validation
+        self.validate_dashboard_schema(out['data'])
+
+
+        out['success'] = True
+        return out
diff --git a/kubePtop/global_attrs.py b/kubePtop/global_attrs.py
index 449c85e..baf000c 100644
--- a/kubePtop/global_attrs.py
+++ b/kubePtop/global_attrs.py
@@ -1,24 +1,38 @@
 
 class GlobalAttrs:
+
+    env_connection_method = ""
+
+    env_prometheus_pod_name = ""
+    env_prometheus_pod_port = "9090"
+    env_prometheus_pod_namespace = "default"
+    env_kube_config_file = ""
+
     env_prometheus_server = "??"
     env_basic_auth_enabled = False
-    env_prometheus_username = None
-    env_prometheus_password = None
+    env_prometheus_username = ""
+    env_prometheus_password = ""
     env_insecure = False
-    
+
     log_dir = "/tmp/"
     log_file = "kptop.log"
 
     exceptions_num = 0
     session = None
 
+    initial_message = "Loading ..."
+
     node_exporter_node_label = "node" #"kubernetes_node"
     kubernetes_exporter_node_label = "instance"
     live_update_interval = 8
     start_graphs_with_zero = True
     graphs_width = 45
-    
+
+    default_dashboards_dir = "/var/kptop/dashboards"
+    default_commands_dir = "/var/kptop/commands"
+
     debug = False
+    version = "v0.0.9"
 
     def __init__(self):
-        pass
\ No newline at end of file
+        pass
diff --git a/kubePtop/helper.py b/kubePtop/helper.py
index 462b2e0..07aa5ee 100644
--- a/kubePtop/helper.py
+++ b/kubePtop/helper.py
@@ -6,6 +6,47 @@ class Helper:
     def __init__(self):
         pass
 
+    def seconds_to_human_readable(self, seconds):
+        units = [
+            ('d', 24 * 3600),
+            ('h', 3600),
+            ('m', 60),
+            ('s', 1)
+        ]
+
+        result = []
+
+        for unit, duration in units:
+            if seconds >= duration:
+                value, seconds = divmod(seconds, duration)
+                result.append(f"{int(value)}{unit}")
+
+        if not result:
+            result.append("0s")
+
+        return ' '.join(result)
+
+    def milliseconds_to_human_readable(self, milliseconds):
+        seconds = milliseconds / 1000
+        units = [
+            ('d', 24 * 3600),
+            ('h', 3600),
+            ('m', 60),
+            ('s', 1)
+        ]
+
+        result = []
+
+        for unit, duration in units:
+            if seconds >= duration:
+                value, seconds = divmod(seconds, duration)
+                result.append(f"{int(value)}{unit}")
+
+        if not result:
+            result.append("0s")
+
+        return ' '.join(result)
+
     def bytes_to_kb_mb_gb(self,size_bytes):
         """
         Converts bytes to kb, mb, gb
@@ -19,6 +60,21 @@ def bytes_to_kb_mb_gb(self,size_bytes):
         s = round(size_bytes / p, 2)
         return "%s %s" % (s, size_name[i])
 
+
+    def bytes_to_kb_mb_gb_split(self, size_bytes):
+        """
+        Converts bytes to kb, mb, gb
+        INPUT: size in bytes
+        RETURNS: (value, unit)
+        """
+        if size_bytes == 0:
+            return (0, "B")
+        size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
+        i = int(math.floor(math.log(size_bytes, 1024)))
+        p = math.pow(1024, i)
+        s = round(size_bytes / p, 2)
+        return (s, size_name[i])
+
     # def bytes_to_kb(self, size_bytes):
     #     """
     #     Converts bytes to kb, mb, gb
@@ -47,7 +103,7 @@ def bytes_to_mb(self, bytes):
         """
         kb = bytes / 1000
         return kb / 1024
-    
+
     def sec_to_m_h(self, total_seconds):
         """
         Converts seconds to Minutes or Hours
@@ -65,7 +121,7 @@ def sec_to_m_h(self, total_seconds):
             unit = "hour/s"
         return f"{out} {unit}"
 
-    
+
     def sec_to_m_h_d(self, total_seconds):
         """
         Converts seconds to Minutes, Hours or Days
@@ -115,3 +171,34 @@ def percentage(self, part, whole):
 
     def convert_epoch_timestamp(self, timestamp):
         return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp))
+
+    def convert_data_unit(self, value, metric_unit):
+        if metric_unit == 'None':
+            return value
+        if value == float('inf'):
+            value = "INF"
+        elif metric_unit == 'byte':
+            value = self.bytes_to_kb_mb_gb(value)
+        elif metric_unit == 'seconds':
+            value =  self.seconds_to_human_readable(value)
+        elif metric_unit == 'milliseconds':
+            value =  self.milliseconds_to_human_readable(value)
+        elif metric_unit == 'timestamp':
+            value =  self.convert_epoch_timestamp(value)
+        elif  metric_unit == 'percentage':
+            value =  f"{round(value)}%"
+        return value
+
+    def safe_eval(self, custom_key, labels):
+        for key, value in labels.items():
+            custom_key = custom_key.replace(f"{{{{{key}}}}}", f"{value}")
+        return custom_key
+
+    def check_thread_status(self, thread):
+        try:
+            if thread.is_alive():
+                return "[green]ALIVE"
+            else:
+                return "[red]DEAD"
+        except Exception as e:
+                return str(e)
diff --git a/kubePtop/old/cli.old.py b/kubePtop/old/cli.old.py
new file mode 100644
index 0000000..f3fd12c
--- /dev/null
+++ b/kubePtop/old/cli.old.py
@@ -0,0 +1,223 @@
+from kubePtop.read_env import ReadEnv
+# Read environment variables
+read_environment_variables = ReadEnv()
+read_environment_variables.read_env()
+import argparse
+from kubePtop.session import PrometheusAPI
+from kubePtop.node_monitor import Node_Monitoring
+from kubePtop.pod_monitor import Pod_Monitoring
+from kubePtop.node_metrics import PrometheusNodeMetrics
+from kubePtop.pod_metrics import PrometheusPodsMetrics
+import rich
+
+node_monitor = Node_Monitoring()
+pod_monitor = Pod_Monitoring()
+pod_metrics = PrometheusPodsMetrics()
+node_metrics = PrometheusNodeMetrics()
+prometheus_api = PrometheusAPI()
+from kubePtop.logging import Logging
+from kubePtop.global_attrs import GlobalAttrs
+
+
+
+class Cli():
+    def __init__(self):
+        self.parser = None
+        # CLI Input attributes
+        # self.verify_prometheus = False
+        self.list_pvcs = False
+        self.list_nodes = False
+        self.node = None
+        self.list_pods = False
+        self.pod = None
+        self.container = None
+        self.namespace = "default"
+        self.all_namespaces = False
+        self.debug = False
+        self.dashboard = 'default'
+        self.list_dashboards = False
+        self.sort_by_mem_usage = False
+        self.list_option = ''
+        self.list_nodes_option = []
+        self.colorize_json = False
+        self.dashboard = None
+
+
+        # Read CLI arguments
+        self.argparse()
+
+
+        if self.debug:
+            GlobalAttrs.debug = True
+            Logging.log.setLevel(level="DEBUG")
+
+        if self.dashboard:
+            rich.print("Testing - Custom Dashboard")
+            exit(1)
+
+
+
+        # kptop nodes <NODE-NAME>
+        if self.node:
+            if self.list_dashboards:
+                node_monitor.list_dashboards()
+                exit(0)
+
+            # kptop nodes <NODE-NAME> -o json
+            if self.list_option == 'json':
+                node_metrics.topNodeJson(node=self.node, color=self.colorize_json)
+                exit(0)
+            # Check if the node found.
+            node_monitor.display_dashboard(dashboard=self.dashboard, node_name=self.node)
+
+        # kptop nodes
+        if self.list_nodes:
+            # kptop nodes -o json
+            if self.list_option == 'json':
+                node_metrics.topNodeJson(node=".*", color=self.colorize_json)
+                exit(0)
+            node_metrics.topNodeTable(option=self.list_option)
+            exit(0)
+
+
+        # kptop pods <POD-NAME>
+        if self.pod:
+            if self.container is None:
+                self.container = ".*"
+            # Check if the pod found.
+            check_pod = pod_metrics.podExists(pod=self.pod, namespace=self.namespace)
+            if not check_pod.get('result'):
+                print(f"pod/{self.pod} not found in the '{self.namespace}' namespace")
+                rich.print(f"[yellow]{check_pod.get('fail_reason')}")
+                exit(1)
+            pod_monitor.pod_monitor(pod=self.pod, namespace=self.namespace, container=self.container)
+
+        if self.list_pods:
+            # kptop pods
+            ns = self.namespace
+            if self.all_namespaces:
+                ns = ".*"
+            pod_metrics.topPodTable(namespace=ns,sort_by_mem_usage=self.sort_by_mem_usage)
+            exit(0)
+
+        if self.list_pvcs:
+            # kptop pods
+            ns = self.namespace
+            if self.all_namespaces:
+                ns = ".*"
+            pod_metrics.topPvcTable(namespace=ns)
+            exit(0)
+
+        # Print help if no args are provided.
+        # self.parser.print_help()
+
+    def argparse(self):
+        parser = argparse.ArgumentParser(description='A Python tool for Kubernetes Nodes/Pods terminal monitoring through Prometheus metrics.')
+        parser.add_argument('top', type=str, nargs='*', metavar='{pods, pod, po}  |  {nodes, node}  |  {persistentvolumeclaim, pvc}', help='top pods/nodes/persistentvolumeclaim')
+        parser.add_argument('-n', '--namespace', type=str, required=False, metavar='', help='Specify a Kubernetes namespace')
+        parser.add_argument('-A', '--all-namespaces', required=False, action='store_true', help='All Kubernetes namespaces')
+        parser.add_argument('-c', '--container', type=str, required=False, metavar='', help='Monitor a specific Pod\'s container')
+        parser.add_argument('-i', '--interval', type=int, required=False, metavar='', help='Live monitoring update interval')
+        parser.add_argument('-V', '--verify-prometheus', required=False, action='store_true', help='Verify Prometheus connection & exporters')
+        parser.add_argument('-C', '--check-metrics', required=False, action='store_true', help='Checks the availability of the needed metrics')
+        parser.add_argument('-d', '--debug', required=False, action='store_true', help='Print debug output')
+        parser.add_argument('-s', '--sort-by-mem-usage', required=False, action='store_true', help='Sort top result by memory usage')
+        parser.add_argument('-o', '--option', type=str, required=False, choices=['cloud', 'json'], help='options for "kptop node||pod" (currently supported in "kptop node")')
+        parser.add_argument('-cj', '--colorize-json', required=False, action='store_true', help='Colorize Json output (with "-o json")')
+        parser.add_argument('-D', '--dashboard', type=str, required=False, metavar='', help='Dashboard name to visualize')
+        # parser.add_argument('-q', '--query', type=str, required=False, help='options for "Run a custom query')
+
+        # parser.add_argument('-D', '--dashboard', type=str, required=False, metavar='', help='Specify a dashboard')
+        # parser.add_argument('-L', '--list-dashboards', required=False, action='store_true', help='List available dashboards')
+
+        pod_aliases = ['pod', 'pods', 'po']
+        node_aliases = ['node', 'nodes']
+        pvc_aliases = ['pvc', 'persistentvolumeclaim']
+
+        results = parser.parse_args()
+        self.parser = parser
+
+        if results.debug:
+            self.debug = True
+
+        ### kptop --verify-prometheus
+        if results.verify_prometheus:
+            prometheus_api.verify_exporters()
+            if results.check_metrics:
+                prometheus_api.check_metrics()
+            exit(0)
+
+
+        if len(results.top) == 0:
+            self.parser.print_help()
+            exit(1)
+
+        ### kptop pods | nodes | pvcs
+        if len(results.top) == 1:
+            if results.top[0] in pod_aliases:
+                self.list_pods = True
+            elif results.top[0] in node_aliases:
+                self.list_nodes = True
+            elif results.top[0] in pvc_aliases:
+                self.list_pvcs = True
+            else:
+                rich.print(f"[bold]ERROR -- unkown argument '{results.top[0]}'\n")
+                self.parser.print_help()
+                exit(1)
+
+        ### Example: kptop pods <POD-NAME>
+        if len(results.top) == 2:
+            if results.top[0] in pod_aliases:
+                self.pod = results.top[1]
+            elif results.top[0] in node_aliases:
+                self.node = results.top[1]
+            else:
+                rich.print(f"[bold]ERROR -- unkown argument '{results.top[0]}'\n")
+                self.parser.print_help()
+                exit(1)
+        if len(results.top) > 2:
+            rich.print(f"[bold]ERROR -- unkown argument '{results.top[2]}' - only 2 arguments are expected\n")
+            self.parser.print_help()
+            exit(1)
+
+        if results.namespace and results.all_namespaces:
+            rich.print("[bold]ERROR -- You can only use '--all-namespaces' or '--namespace' \n")
+            self.parser.print_help()
+            exit(1)
+
+        if results.namespace:
+            self.namespace = results.namespace
+
+        if results.option:
+            self.list_option = results.option
+
+        if results.colorize_json:
+            self.colorize_json = results.option
+
+        if results.all_namespaces:
+            self.all_namespaces = results.all_namespaces
+
+        if results.container:
+            self.container = results.container
+
+        if results.interval:
+            GlobalAttrs.live_update_interval = results.interval
+
+        if results.dashboard:
+            self.dashboard = results.dashboard
+
+        # if results.list_dashboards:
+        #     self.list_dashboards = True
+
+        # if results.dashboard:
+        #     self.dashboard = results.dashboard
+
+        if results.sort_by_mem_usage:
+            self.sort_by_mem_usage = True
+
+
+
+cli = Cli()
+
+# def run():
+#     cli = Cli()
diff --git a/kubePtop/cli.py b/kubePtop/old/cli.py
similarity index 95%
rename from kubePtop/cli.py
rename to kubePtop/old/cli.py
index 0912301..f3fd12c 100644
--- a/kubePtop/cli.py
+++ b/kubePtop/old/cli.py
@@ -1,4 +1,3 @@
-from kubePtop.global_attrs import GlobalAttrs
 from kubePtop.read_env import ReadEnv
 # Read environment variables
 read_environment_variables = ReadEnv()
@@ -17,6 +16,8 @@
 node_metrics = PrometheusNodeMetrics()
 prometheus_api = PrometheusAPI()
 from kubePtop.logging import Logging
+from kubePtop.global_attrs import GlobalAttrs
+
 
 
 class Cli():
@@ -39,7 +40,8 @@ def __init__(self):
         self.list_option = ''
         self.list_nodes_option = []
         self.colorize_json = False
-        
+        self.dashboard = None
+
 
         # Read CLI arguments
         self.argparse()
@@ -49,12 +51,18 @@ def __init__(self):
             GlobalAttrs.debug = True
             Logging.log.setLevel(level="DEBUG")
 
+        if self.dashboard:
+            rich.print("Testing - Custom Dashboard")
+            exit(1)
+
+
+
         # kptop nodes <NODE-NAME>
         if self.node:
             if self.list_dashboards:
                 node_monitor.list_dashboards()
                 exit(0)
-            
+
             # kptop nodes <NODE-NAME> -o json
             if self.list_option == 'json':
                 node_metrics.topNodeJson(node=self.node, color=self.colorize_json)
@@ -83,7 +91,7 @@ def __init__(self):
                 rich.print(f"[yellow]{check_pod.get('fail_reason')}")
                 exit(1)
             pod_monitor.pod_monitor(pod=self.pod, namespace=self.namespace, container=self.container)
-        
+
         if self.list_pods:
             # kptop pods
             ns = self.namespace
@@ -116,6 +124,7 @@ def argparse(self):
         parser.add_argument('-s', '--sort-by-mem-usage', required=False, action='store_true', help='Sort top result by memory usage')
         parser.add_argument('-o', '--option', type=str, required=False, choices=['cloud', 'json'], help='options for "kptop node||pod" (currently supported in "kptop node")')
         parser.add_argument('-cj', '--colorize-json', required=False, action='store_true', help='Colorize Json output (with "-o json")')
+        parser.add_argument('-D', '--dashboard', type=str, required=False, metavar='', help='Dashboard name to visualize')
         # parser.add_argument('-q', '--query', type=str, required=False, help='options for "Run a custom query')
 
         # parser.add_argument('-D', '--dashboard', type=str, required=False, metavar='', help='Specify a dashboard')
@@ -130,7 +139,7 @@ def argparse(self):
 
         if results.debug:
             self.debug = True
-        
+
         ### kptop --verify-prometheus
         if results.verify_prometheus:
             prometheus_api.verify_exporters()
@@ -155,7 +164,7 @@ def argparse(self):
                 rich.print(f"[bold]ERROR -- unkown argument '{results.top[0]}'\n")
                 self.parser.print_help()
                 exit(1)
-        
+
         ### Example: kptop pods <POD-NAME>
         if len(results.top) == 2:
             if results.top[0] in pod_aliases:
@@ -178,10 +187,10 @@ def argparse(self):
 
         if results.namespace:
             self.namespace = results.namespace
-            
+
         if results.option:
             self.list_option = results.option
-            
+
         if results.colorize_json:
             self.colorize_json = results.option
 
@@ -194,6 +203,9 @@ def argparse(self):
         if results.interval:
             GlobalAttrs.live_update_interval = results.interval
 
+        if results.dashboard:
+            self.dashboard = results.dashboard
+
         # if results.list_dashboards:
         #     self.list_dashboards = True
 
diff --git a/kubePtop/node_metrics.py b/kubePtop/old/node_metrics.py
similarity index 92%
rename from kubePtop/node_metrics.py
rename to kubePtop/old/node_metrics.py
index fb34e08..79b177d 100644
--- a/kubePtop/node_metrics.py
+++ b/kubePtop/old/node_metrics.py
@@ -1289,7 +1289,7 @@ def nodeDiskReadBytes(self, node):
     #     return output
 
 
-    def topNode(self, node=".*"):
+    def topNode(self, node=".*", option=""):
         """
         """
         output = {
@@ -1308,25 +1308,38 @@ def topNode(self, node=".*"):
                 return output
 
             nodes_dct = {}
+            
             for node_ in memory_total.get('data').get('result'):
-                nodes_dct[node_.get('metric').get(GlobalAttrs.node_exporter_node_label)] = {
-                    "memory_total": int(node_.get('value')[1]),
-                    "memory_free": -1,
-                    "memory_used": -1,
-                    "cpu_cores": -1,
-                    # "cpu_used": -1, # not sure of the metrics to get the used cpu in milicores.
-                    "cpu_used_percentage": -1,
-                    "running_pods_num": -1,
-                    "cluster": "",
-                    "node_os": "",
-                    "node_arch": "",
-                    "region": "",
-                    "az": "",
-                    "instance_type": "",
-                    "cluster_env": "Unknown",
-                    "node_group_capacity_type": "",
-                    "node_group_name": "",
-                }
+                
+                if (option == 'cloud') or (option == 'json'):
+                    nodes_dct[node_.get('metric').get(GlobalAttrs.node_exporter_node_label)] = {
+                        "memory_total": int(node_.get('value')[1]),
+                        "memory_free": -1,
+                        "memory_used": -1,
+                        "cpu_cores": -1,
+                        # "cpu_used": -1, # not sure of the metrics to get the used cpu in milicores.
+                        "cpu_used_percentage": -1,
+                        "running_pods_num": -1,
+                        "cluster": "?",
+                        "node_os": "?",
+                        "node_arch": "?",
+                        "region": "?",
+                        "az": "?",
+                        "instance_type": "?",
+                        "cluster_env": "Unknown",
+                        "node_group_capacity_type": "?",
+                        "node_group_name": "?",
+                    }
+                else:
+                    nodes_dct[node_.get('metric').get(GlobalAttrs.node_exporter_node_label)] = {
+                        "memory_total": int(node_.get('value')[1]),
+                        "memory_free": -1,
+                        "memory_used": -1,
+                        "cpu_cores": -1,
+                        # "cpu_used": -1, # not sure of the metrics to get the used cpu in milicores.
+                        "cpu_used_percentage": -1,
+                        "running_pods_num": -1,
+                    }
 
             memory_free_query = f'node_memory_MemFree_bytes{{{GlobalAttrs.node_exporter_node_label}=~"{node}"}}'
             memory_free = self.run_query(memory_free_query)
@@ -1366,12 +1379,12 @@ def topNode(self, node=".*"):
                 return output
                 
             ## 
-            node_managed_k8s_info = self.nodeManagedK8sInfo(node=node)
-            if not node_managed_k8s_info.get('success'):
-                output['fail_reason'] = node_managed_k8s_info.get('fail_reason')
-                return output
+            if (option == 'cloud') or (option == 'json'):
+                node_managed_k8s_info = self.nodeManagedK8sInfo(node=node)
+                if not node_managed_k8s_info.get('success'):
+                    output['fail_reason'] = node_managed_k8s_info.get('fail_reason')
+                    return output
         
-            
             for node in memory_free.get('data').get('result'):
                 nodes_dct[node.get('metric').get(GlobalAttrs.node_exporter_node_label)]['memory_free'] = int(node.get('value')[1])
                 nodes_dct[node.get('metric').get(GlobalAttrs.node_exporter_node_label)]['memory_used'] = nodes_dct[node.get('metric').get(GlobalAttrs.node_exporter_node_label)]['memory_total'] - int(node.get('value')[1])
@@ -1391,29 +1404,36 @@ def topNode(self, node=".*"):
                 except KeyError:
                     pass # A KeyError Exception is expected as this metric returns the value for the master nodes while other metrics dont.
                     
+            # rich.print(node_managed_k8s_info)
+            if (option == 'cloud') or (option == 'json'):
+                for node in node_managed_k8s_info.get('result'):
+                    # General Labels (match different cloud providers)
+                    # rich.print(node_managed_k8s_info.get('result'))
+                    try:
+                        nodes_dct[node.get('metric').get('instance')]['node_arch'] = node['metric']['beta_kubernetes_io_arch']
+                        nodes_dct[node.get('metric').get('instance')]['node_os'] = node['metric']['beta_kubernetes_io_os']
+                        nodes_dct[node.get('metric').get('instance')]['region'] = node['metric']['topology_kubernetes_io_region']
+                        nodes_dct[node.get('metric').get('instance')]['az'] = node['metric']['topology_kubernetes_io_zone']
+                        nodes_dct[node.get('metric').get('instance')]['instance_type'] = node['metric']['node_kubernetes_io_instance_type'] 
+                        nodes_dct[node.get('metric').get('instance')]['node_group_name'] = node['metric']['eks_amazonaws_com_nodegroup']                    
+                                          
+                    except KeyError:
+                        pass # If labels are not found, means that most probably this is a Local cluster
+
+                    try:
+                        nodes_dct[node.get('metric').get('instance')]['cluster'] = node['metric']['cluster']
+                    except:
+                        pass # If labels are not found, means that most probably this is a Local cluster
+                    
+                    # AWS Labels
+                    try:
+                        nodes_dct[node.get('metric').get('instance')]['node_group_capacity_type'] = node['metric']['eks_amazonaws_com_capacityType']
+                        nodes_dct[node.get('metric').get('instance')]['node_group_name'] = node['metric']['eks_amazonaws_com_nodegroup']
+                        if nodes_dct[node.get('metric').get('instance')]['node_group_name']:
+                            nodes_dct[node.get('metric').get('instance')]['cluster_env'] = 'EKS'
+                    except KeyError:
+                        pass # If labels are not found, means that it's not an EKS cluster.
             
-            for node in node_managed_k8s_info.get('result'):
-                # General Labels (match different cloud providers)
-                try:
-                    nodes_dct[node.get('metric').get('instance')]['node_arch'] = node['metric']['beta_kubernetes_io_arch']
-                    nodes_dct[node.get('metric').get('instance')]['node_os'] = node['metric']['beta_kubernetes_io_os']
-                    nodes_dct[node.get('metric').get('instance')]['cluster'] = node['metric']['cluster']
-                    nodes_dct[node.get('metric').get('instance')]['region'] = node['metric']['topology_kubernetes_io_region']
-                    nodes_dct[node.get('metric').get('instance')]['az'] = node['metric']['topology_kubernetes_io_zone']
-                    nodes_dct[node.get('metric').get('instance')]['instance_type'] = node['metric']['node_kubernetes_io_instance_type']
-                except KeyError:
-                    pass # If labels are not found, means that most probably this is a Local cluster
-                
-                # AWS Labels
-                try:
-                    nodes_dct[node.get('metric').get('instance')]['node_group_capacity_type'] = node['metric']['eks_amazonaws_com_capacityType']
-                    nodes_dct[node.get('metric').get('instance')]['node_group_name'] = node['metric']['eks_amazonaws_com_nodegroup']
-                    if nodes_dct[node.get('metric').get('instance')]['node_group_name']:
-                        nodes_dct[node.get('metric').get('instance')]['cluster_env'] = 'EKS'
-                except KeyError:
-                    pass # If labels are not found, means that it's not an EKS cluster.
-            
-
             output['result'] = nodes_dct
             output['success'] = True
 
@@ -1426,7 +1446,7 @@ def topNode(self, node=".*"):
         return output
     
     def topNodeJson(self, node=".*", color=False):
-        nodes_dct = self.topNode(node=node)
+        nodes_dct = self.topNode(node=node, option='json')
         if not nodes_dct.get('success'):
             print(f"ERROR -- Failed to get nodes \n{nodes_dct.get('fail_reason')}")
             exit(1)
@@ -1440,7 +1460,7 @@ def topNodeJson(self, node=".*", color=False):
     def topNodeTable(self, option=""):
         """
         """
-        nodes_json = self.topNode()
+        nodes_json = self.topNode(option=option)
         # import rich
         # rich.print(nodes_json)
         if not nodes_json.get('success'):
@@ -1450,10 +1470,10 @@ def topNodeTable(self, option=""):
 
         table = [['NODE', 'MEM TOTAL', 'MEM USAGE', 'MEM FREE', 'CPU CORES', 'CPU USAGE%', 'RUNNING PODS' ]]
         if option == 'cloud':
-            table = [['NODE', 'MEM TOTAL', 'MEM USAGE', 'MEM FREE', 'CPU CORES', 'CPU USAGE%', 'RUNNING PODS', 'CLUSTER', 'INSTANCE TYPE', 'AZ', 'ENV', 'NG CAPACITY TYPE']]
+            table = [['NODE', 'MEM TOTAL', 'MEM USAGE', 'MEM FREE', 'CPU CORES', 'CPU USAGE%', 'RUNNING PODS', 'CLUSTER', 'INSTANCE TYPE', 'AZ', 'ENV', 'NG CAPACITY TYPE', 'NG']]
             
         if option == 'cloud':
-            for  node, value in nodes_json.get('result').items():
+            for node, value in nodes_json.get('result').items():
                 row = [
                         node,
                         helper_.bytes_to_kb_mb_gb(value.get('memory_total')),
@@ -1468,7 +1488,7 @@ def topNodeTable(self, option=""):
                         value.get('az'),
                         value.get('cluster_env'),
                         value.get('node_group_capacity_type'),
-                        # value.get('node_group_name'),
+                        value.get('node_group_name'),
                     ]
                 table.append(row)
         else:
@@ -1501,7 +1521,7 @@ def nodeManagedK8sInfo(self, node):
             "result": {}
         }
         try:
-            query = f'kubelet_node_name{{kubernetes_io_hostname=~"{node}"}}'
+            query = f'kubelet_node_name{{kubernetes_io_hostname=~"{node}"}}' # 'machine_cpu_cores' also has the needed labels
             result = self.run_query(query)
             if not result.get('status') == 'success':
                 output['fail_reason'] =  f"could not get metric's value: \n{query}"
diff --git a/kubePtop/node_monitor.py b/kubePtop/old/node_monitor.py
similarity index 100%
rename from kubePtop/node_monitor.py
rename to kubePtop/old/node_monitor.py
diff --git a/kubePtop/pod_metrics.py b/kubePtop/old/pod_metrics.py
similarity index 100%
rename from kubePtop/pod_metrics.py
rename to kubePtop/old/pod_metrics.py
diff --git a/kubePtop/pod_monitor.py b/kubePtop/old/pod_monitor.py
similarity index 100%
rename from kubePtop/pod_monitor.py
rename to kubePtop/old/pod_monitor.py
diff --git a/kubePtop/old/prometheus_http.yml b/kubePtop/old/prometheus_http.yml
new file mode 100644
index 0000000..5f0c7ed
--- /dev/null
+++ b/kubePtop/old/prometheus_http.yml
@@ -0,0 +1,21 @@
+dataSoures:
+  - name: staging prometheus
+    type: prometheus # || prometheusPodPortForward || KubernetesAPI
+    prometheusOptions:
+      prometheusEndpoint: http://..
+      basicAuthEnabled: false
+      basicAuthUsernameEnv: abc
+      basicAuthPasswordEnv: abc
+
+  - name: staging prometheus
+    type: prometheusPodPortForward
+    prometheusPodPortForwardOptions:
+      prometheusPodName: prometheus-0
+      prometheusPodNamespace: monitoring
+      kubeConfigFilePath: /Users/USER/.kube/config #~/.kube/config # default
+
+  - name: staging eks
+    type: KubernetesAPI # || prometheusPodPortForward || KubernetesAPI
+    KubernetesAPIOptions:
+      kubeConfigFilePath: /Users/USER/.kube/config #~/.kube/config # default
+      kubeProfile: abc
diff --git a/kubePtop/read_env.py b/kubePtop/read_env.py
index 47d9d87..be98918 100644
--- a/kubePtop/read_env.py
+++ b/kubePtop/read_env.py
@@ -1,33 +1,84 @@
 import os
 from kubePtop.global_attrs import GlobalAttrs
-gattrs = GlobalAttrs()
 
 class ReadEnv:
     def __init__(self):
         pass
 
+    def env_to_bool(self, value):
+        if value.lower() == 'true':
+            return True
+        return False
+
+
+    def check_env(self, envs):
+        """Checks if the ENV is defined
+
+        Args:
+            env (lst): takes a list of ENVs
+        Return: dct
+        """
+        output = {
+            "missing": False,
+            "missing_envs": []
+        }
+        for env in envs:
+            try:
+                os.environ[f'{env}']
+            except KeyError as e:
+                output['missing'] = True
+                output['missing_envs'].append(env)
+        return output
+
+
     def read_env(self):
         """
         Read Environment variables
         """
 
-        # Mandatory ENVs
-        try:
-            GlobalAttrs.env_prometheus_server  = os.environ['KPTOP_PROMETHEUS_SERVER']
-        except (KeyError) as e:
-            raise SystemExit(f"\nERROR -- ENV not found => {e}")
+        check_conn_method = self.check_env(['KPTOP_CONNECTION_METHOD'])
+        if check_conn_method['missing']:
+            print(f"INFO -- ENV: {check_conn_method.get('missing_envs')} is missing\n")
+            # print('github link')
+            exit(1)
+
+
+        if os.environ['KPTOP_CONNECTION_METHOD'] not in ['pod_portForward', 'prometheus_endpoint']:
+            print("ERROR -- KPTOP_CONNECTION_METHOD allowed options are: 'pod_portForward' or 'prometheus_endpoint' ")
+            # print('github link')
+            exit(1)
 
-        # Basic Auth ENVs
         try:
-            if os.environ['KPTOP_BASIC_AUTH_ENABLED']:
-                GlobalAttrs.env_basic_auth_enabled   = os.environ['KPTOP_BASIC_AUTH_ENABLED']
-                GlobalAttrs.env_prometheus_username  = os.environ['KPTOP_PROMETHEUS_USERNAME']
-                GlobalAttrs.env_prometheus_password  = os.environ['KPTOP_PROMETHEUS_PASSWORD']
+            if os.environ['KPTOP_CONNECTION_METHOD'] == "pod_portForward":
+                GlobalAttrs.env_connection_method = os.environ['KPTOP_CONNECTION_METHOD']
+
+                check = self.check_env(['KPTOP_PROMETHEUS_POD_NAME', 'KPTOP_PROMETHEUS_POD_PORT', 'KPTOP_PROMETHEUS_POD_NAMESPACE'])
+                if check['missing']:
+                    print(f"INFO -- ENVs: {check.get('missing_envs')} are missing")
+                    exit(1)
+
+                GlobalAttrs.env_prometheus_pod_name = os.environ['KPTOP_PROMETHEUS_POD_NAME']
+                GlobalAttrs.env_prometheus_pod_port = os.environ['KPTOP_PROMETHEUS_POD_PORT']
+                GlobalAttrs.env_prometheus_pod_namespace = os.environ['KPTOP_PROMETHEUS_POD_NAMESPACE']
+
+
+            if os.environ['KPTOP_CONNECTION_METHOD'] == "prometheus_endpoint":
+                GlobalAttrs.env_connection_method = os.environ['KPTOP_CONNECTION_METHOD']
 
-            if GlobalAttrs.env_basic_auth_enabled:
-                if (GlobalAttrs.env_prometheus_username is None or GlobalAttrs.env_prometheus_password is None):
-                    raise SystemExit("INFO -- ENV: KPTOP_PROMETHEUS_USERNAME or KPTOP_PROMETHEUS_PASSWORD is missing")
+                check = self.check_env(['KPTOP_PROMETHEUS_SERVER'])
+                if check['missing']:
+                    print(f"INFO -- ENVs: {check.get('missing_envs')} are missing")
+                    exit(1)
+                GlobalAttrs.env_prometheus_server  = os.environ['KPTOP_PROMETHEUS_SERVER']
 
+                if os.environ['KPTOP_BASIC_AUTH_ENABLED']:
+                    check = self.check_env(['KPTOP_PROMETHEUS_USERNAME', 'KPTOP_PROMETHEUS_PASSWORD'])
+                    if check['missing']:
+                        print(f"INFO -- ENVs: {check.get('missing_envs')} are missing")
+                        exit(1)
+                    GlobalAttrs.env_basic_auth_enabled   = os.environ['KPTOP_BASIC_AUTH_ENABLED']
+                    GlobalAttrs.env_prometheus_username  = os.environ['KPTOP_PROMETHEUS_USERNAME']
+                    GlobalAttrs.env_prometheus_password  = os.environ['KPTOP_PROMETHEUS_PASSWORD']
 
             if GlobalAttrs.env_basic_auth_enabled not in [True, False, 'true', 'false']:
                 print("INFO -- KPTOP_BASIC_AUTH_ENABLED > allowed options are: 'true' || 'false'")
@@ -39,20 +90,26 @@ def read_env(self):
         except (KeyError) as e:
             SystemExit(f"\nERROR -- ENV not found => {e}")
 
-    
+
         # Optional ENVs
+
         try:
-            GlobalAttrs.node_exporter_node_label  = os.environ['KPTOP_NODE_EXPORTER_NODE_LABEL']
+            GlobalAttrs.env_kube_config_file  = os.environ['KUBECONFIG']
         except:
             pass
 
+        # try:
+        #     GlobalAttrs.node_exporter_node_label  = os.environ['KPTOP_NODE_EXPORTER_NODE_LABEL']
+        # except:
+        #     pass
+
         try:
-            GlobalAttrs.env_insecure  = os.environ['KPTOP_INSECURE']
+            GlobalAttrs.env_insecure  = self.env_to_bool(os.environ['KPTOP_INSECURE'])
         except:
             pass
-    
+
         try:
-            GlobalAttrs.start_graphs_with_zero = os.environ['KPTOP_START_GRAPHS_WITH_ZERO']
+            GlobalAttrs.start_graphs_with_zero = self.env_to_bool(os.environ['KPTOP_START_GRAPHS_WITH_ZERO'])
         except:
             pass
 
@@ -64,4 +121,14 @@ def read_env(self):
         try:
             GlobalAttrs.graphs_width = int(os.environ['KPTOP_GRAPH_WIDTH'])
         except:
-            pass
\ No newline at end of file
+            pass
+
+        try:
+            GlobalAttrs.default_dashboards_dir = os.environ['KPTOP_DEFAULT_DASHBOARDS_DIRECTORY']
+        except:
+            pass
+
+        try:
+            GlobalAttrs.default_commands_dir = os.environ['KPTOP_DEFAULT_COMMANDS_DIRECTORY']
+        except:
+            pass
diff --git a/kubePtop/requirements.txt b/kubePtop/requirements.txt
index 7484f58..370aac3 100644
--- a/kubePtop/requirements.txt
+++ b/kubePtop/requirements.txt
@@ -1,5 +1,7 @@
-rich==13.3.1
+rich==13.6.0
 requests==2.28.2
 tabulate==0.9.0
 argparse
-asciichartpy==1.5.25
\ No newline at end of file
+asciichartpy==1.5.25
+kubernetes==26.1.0
+cerberus==1.3.5
diff --git a/kubePtop/session.py b/kubePtop/session.py
index 39f48eb..12c1186 100644
--- a/kubePtop/session.py
+++ b/kubePtop/session.py
@@ -11,7 +11,118 @@
 # Ignore Warning
 requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
 # https://stackoverflow.com/a/41041028
-requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
+# requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
+
+import socket
+import six.moves.urllib.request as urllib_request
+import urllib.parse
+from kubernetes import config
+from kubernetes.client import Configuration
+from kubernetes.client.api import core_v1_api
+from kubernetes.client.rest import ApiException
+from kubernetes.stream import portforward
+import traceback
+
+class KubernetesPodPortForward:
+    def __init__(self, api_object, pod_name, pod_port, namespace) :
+        self.k8s_port_forward_socket = None
+        self.core_v1 = api_object
+
+        self.prometheus_pod_k8s_internal_endpoint = None
+
+        self.namespace = namespace
+        self.pod_name = pod_name
+        self.pod_port = pod_port
+
+    def createConnection(self, address, *args, **kwargs):
+        pf = portforward(self.core_v1.connect_get_namespaced_pod_portforward,
+                        self.pod_name, self.namespace, ports=str(self.pod_port))
+        return pf.socket(int(self.pod_port))
+
+    def runSocket(self):
+        self.k8s_port_forward_socket = socket.create_connection = self.createConnection
+        return self.k8s_port_forward_socket
+
+    def sendRequest(self, path='/-/healthy'):
+        try:
+            if self.k8s_port_forward_socket is None:
+                socket_ = self.runSocket()
+                self.k8s_port_forward_socket = socket_
+                rich.print(f"[grey69]INFO [Beta-Feature] -- Port-forward socket created for pod: '{self.pod_name}' namespace: '{self.namespace}'")
+                logging.log.info(f"INFO [Beta-Feature] -- Port-forward socket created for pod: '{self.pod_name}' namespace: '{self.namespace}'")
+                # print(self.k8s_port_forward_socket)
+
+            url = f'http://{self.pod_name}.pod.{self.namespace}.kubernetes:{self.pod_port}'
+
+            request = urllib_request.urlopen(
+            url + path)
+
+            class Response:
+                    exit_code = request.code
+                    reason = request.reason
+                    text = request.read().decode('utf-8')
+
+            res = Response()
+            return res
+        except ApiException as e:
+            print(f"Erorr -- can't port-forward pod connection")
+            print(e)
+            exit(1)
+        except KeyboardInterrupt as e:
+            print(f"\nOk.")
+            exit(1)
+        except Exception as e:
+            print(f"Error -- {e}")
+            traceback.print_exc()
+            # print(e)
+            exit(1)
+        # request.close()
+        # print('Status Code: %s' % request.code)
+        # print('Reason: %s' % request.reason)
+        # print(text)
+
+    def runQuery(self, query, path='/api/v1/query?'):
+        try:
+            if self.k8s_port_forward_socket is None:
+                socket_ = self.runSocket()
+                self.k8s_port_forward_socket = socket_
+                # print(self.k8s_port_forward_socket)
+                rich.print(f"[grey69]INFO [Beta-Feature] -- Port-forward socket created for pod: '{self.pod_name}' namespace: '{self.namespace}'")
+                logging.log.info(f"INFO [Beta-Feature] -- Port-forward socket created for pod: '{self.pod_name}' namespace: '{self.namespace}'")
+
+                # print(self.k8s_port_forward_socket)
+
+            url = f'http://{self.pod_name}.pod.{self.namespace}.kubernetes:{self.pod_port}'
+            params = urllib.parse.urlencode({'query': f'{query}'})
+
+            # print(url + path + "%s" % params)
+            # http://prometheus-server-0.pod.monitoring.kubernetes:9090/api/v1/query?query=node_cpu_seconds_total
+
+            request = urllib_request.urlopen(
+            url + path + "%s" % params)
+            text = request.read().decode('utf-8')
+
+            if request.code == 200:
+                return json.loads(text)
+            else:
+                return {}
+        except ApiException as e:
+            print(f"Erorr -- can't port-forward pod connection")
+            print(e)
+            exit(1)
+        except KeyboardInterrupt as e:
+            print(f"\nOk.")
+            exit(1)
+        except Exception as e:
+            print(f"Error -- {e}")
+            traceback.print_exc()
+            # print(e)
+            exit(1)
+        # request.close()
+        # print('Status Code: %s' % request.code)
+        # print('Reason: %s' % request.reason)
+        # print(text)
+
 
 class PrometheusAPI:
 
@@ -21,6 +132,63 @@ def __init__(self):
         self.prometheus_url = GlobalAttrs.env_prometheus_server
         self.prometheus_url_query = self.prometheus_url + "/api/v1/query"
 
+        self.core_v1 = None
+
+        # Pod-PortForward object
+        self.pf = None
+        # if GlobalAttrs.env_connection_method == "pod_portForward":
+        #     self.K8s_authenticate()
+
+
+    def K8s_authenticate(self):
+        pod_name = GlobalAttrs.env_prometheus_pod_name
+        pod_port = GlobalAttrs.env_prometheus_pod_port
+        pod_namespace = GlobalAttrs.env_prometheus_pod_namespace
+
+        if GlobalAttrs.env_kube_config_file:
+            config.load_kube_config(
+                config_file=GlobalAttrs.env_kube_config_file
+            )
+        else:
+            config.load_kube_config()
+        # c = Configuration.get_default_copy()
+        # c.assert_hostname = False
+        # Configuration.set_default(c)
+        self.core_v1 = core_v1_api.CoreV1Api()
+
+        self.pf = KubernetesPodPortForward(
+                    api_object=self.core_v1,
+                    pod_name=pod_name,
+                    pod_port=pod_port,
+                    namespace=pod_namespace)
+
+        rich.print("[grey69]INFO [Beta-Feature] -- Authenticating K8s KubeConfig")
+        Logging.log.info(f"INFO [Beta-Feature] -- Authenticating K8s KubeConfig")
+        # Checking if the Prometheus pod exists
+        pod_check = self.K8s_APIs_podExists(pod_name, pod_namespace)
+        if not pod_check.get('found'):
+            print(f"ERROR -- Prometheus Pod '{pod_name}' does NOT exist in the '{pod_namespace}' namespace ")
+            Logging.log.error(f"ERROR -- Prometheus Pod '{pod_name}' does NOT exist in the '{pod_namespace}' namespace \n{pod_check.get('fail_reason')}")
+            rich.print(f"[light_yellow3]{pod_check.get('fail_reason')}")
+            exit(1)
+
+    def K8s_APIs_podExists(self, pod_name, namespace):
+        """Checks if a pod exists
+        returns: (bool)
+        """
+        output = {
+            "found": False,
+            "fail_reason": ""
+        }
+        try:
+            self.core_v1.read_namespaced_pod(name=pod_name,
+                                            namespace=namespace)
+            output['found'] = True
+        except Exception as e:
+            output['fail_reason'] = e
+            # traceback.print_exc()
+        return output
+
     def get_session(self):
         try:
             session = requests.Session()
@@ -69,38 +237,93 @@ def verify_prometheus_connection(self):
             "reason": "",
             "fail_reason": ""
         }
-        session = requests.Session()
-        session.verify = self.verify
-        try:
-            if GlobalAttrs.debug:
-                print("DEBUG -- Checking Prometheus existing connection")
-            Logging.log.info("Checking Prometheus existing connection")
-            prometheus_url = self.prometheus_url + "/-/healthy"
-            if GlobalAttrs.debug:
-                print(f"DEBUG -- Connecting to Prometheus: {prometheus_url}")
-            if GlobalAttrs.env_basic_auth_enabled:
-                req = session.get(prometheus_url, auth=(GlobalAttrs.env_prometheus_username, GlobalAttrs.env_prometheus_password))
-            else:
-                req = session.get(prometheus_url)
-            if req.status_code == 200:
-                Logging.log.info(f"connected successfully, status_code: {req.status_code}")
+
+        if GlobalAttrs.env_connection_method == 'pod_portForward':
+            try:
                 if GlobalAttrs.debug:
-                    print(f"DEBUG -- connected successfully, status_code: {req.status_code}")
-                out["connected"] = True
-                out["status_code"] = req.status_code
-            else:
-                out["status_code"] = req.status_code
-                out["reason"] = req.reason
-                out["fail_reason"] = f"Failed to connect to Prometheus. Reason: {req.reason}"
-                Logging.log.error(f"Failed to connect to Prometheus. Reason: {req.reason}")
-        except Exception as e:
-            out["fail_reason"] = f"Failed to connect to Prometheus; {e}"
-            out["reason"] = "unable to connnect"
-            Logging.log.info(f"Failed to connect to Prometheus; {e}")
+                    print("DEBUG -- Checking Prometheus existing connection")
+                Logging.log.info("Checking Prometheus existing connection")
+                path = "/-/healthy"
+                prometheus_url = self.prometheus_url + path
+                if GlobalAttrs.debug:
+                    print(f"DEBUG -- Connecting to Prometheus: {prometheus_url}")
+
+                req = self.get_request_raw_portForward(path=path)
+                if req.exit_code == 200:
+                    Logging.log.info(f"connected successfully, status_code: {req.exit_code}")
+                    if GlobalAttrs.debug:
+                        print(f"DEBUG -- connected successfully, status_code: {req.exit_code}")
+                    out["connected"] = True
+                    out["status_code"] = req.exit_code
+                    out["reason"] = req.reason
+                else:
+                    out["status_code"] = req.exit_code
+                    out["reason"] = req.reason
+                    out["fail_reason"] = f"Failed to connect to Prometheus. Reason: {req.reason}"
+                    Logging.log.error(f"Failed to connect to Prometheus. Reason: {req.reason}")
+            except Exception as e:
+                out["fail_reason"] = f"Failed to connect to Prometheus; {e}"
+                out["reason"] = "unable to connnect"
+                Logging.log.info(f"Failed to connect to Prometheus; {e}")
 
-        return out
+            return out
 
-    def run_query(self, query):
+        elif GlobalAttrs.env_connection_method == 'prometheus_endpoint':
+            session = requests.Session()
+            session.verify = self.verify
+            try:
+                if GlobalAttrs.debug:
+                    print("DEBUG -- Checking Prometheus existing connection")
+                Logging.log.info("Checking Prometheus existing connection")
+                prometheus_url = self.prometheus_url + "/-/healthy"
+                if GlobalAttrs.debug:
+                    print(f"DEBUG -- Connecting to Prometheus: {prometheus_url}")
+                if GlobalAttrs.env_basic_auth_enabled:
+                    req = session.get(prometheus_url, auth=(GlobalAttrs.env_prometheus_username, GlobalAttrs.env_prometheus_password))
+                else:
+                    req = session.get(prometheus_url)
+                if req.status_code == 200:
+                    Logging.log.info(f"connected successfully, status_code: {req.status_code}")
+                    if GlobalAttrs.debug:
+                        print(f"DEBUG -- connected successfully, status_code: {req.status_code}")
+                    out["connected"] = True
+                    out["status_code"] = req.status_code
+                    out["reason"] = req.reason
+                else:
+                    out["status_code"] = req.status_code
+                    out["reason"] = req.reason
+                    out["fail_reason"] = f"Failed to connect to Prometheus. Reason: {req.reason}"
+                    Logging.log.error(f"Failed to connect to Prometheus. Reason: {req.reason}")
+            except Exception as e:
+                out["fail_reason"] = f"Failed to connect to Prometheus; {e}"
+                out["reason"] = "unable to connnect"
+                Logging.log.info(f"Failed to connect to Prometheus; {e}")
+
+            return out
+
+    def run_query_pod_portForward(self, query):
+        if self.core_v1 is None:
+            self.K8s_authenticate()
+        # pf = KubernetesPodPortForward(
+        #     api_object=self.core_v1,
+        #     pod_name=GlobalAttrs.env_prometheus_pod_name,
+        #     pod_port=GlobalAttrs.env_prometheus_pod_port,
+        #     namespace=GlobalAttrs.env_prometheus_pod_namespace)
+        result = self.pf.runQuery(query)
+        return result
+
+    def get_request_raw_portForward(self, path='/api/v1/query?'):
+        if self.core_v1 is None:
+            self.K8s_authenticate()
+        # pf = KubernetesPodPortForward(
+        #     api_object=self.core_v1,
+        #     pod_name=GlobalAttrs.env_prometheus_pod_name,
+        #     pod_port=GlobalAttrs.env_prometheus_pod_port,
+        #     namespace=GlobalAttrs.env_prometheus_pod_namespace)
+        result = self.pf.sendRequest(path)
+        return result
+
+    def run_query_prometheus_endpoint(self, query):
         if self.session is None:
             if GlobalAttrs.debug:
                 Logging.log.debug(f"While running a query .. establishing a new connection with Prometheus.")
@@ -133,7 +356,15 @@ def run_query(self, query):
             print(f"ERROR -- Failed to connect to Prometheus: Connection Failed\n")
             Logging.log.error(f"Query did NOT run successfully, {e}")
             raise SystemExit(f"> {e}")
-            
+
+    def run_query(self, query):
+        if GlobalAttrs.env_connection_method == 'prometheus_endpoint':
+            return self.run_query_prometheus_endpoint(query)
+        elif GlobalAttrs.env_connection_method == 'pod_portForward':
+            if self.core_v1 is None:
+                self.K8s_authenticate()
+            return self.run_query_pod_portForward(query)
+
     def verifyNodeExporter(self):
         """
         not in use at the moment
@@ -145,20 +376,38 @@ def verifyNodeExporter(self):
         }
         try:
             query = 'sum(node_exporter_build_info) by (version)'
-            result = self.run_query(query)
-            if not result.get('status') == 'success':
-                output['fail_reason'] = f"could not get metric value:\n {query}"
-                return output
 
-            if not result.get('data').get('result'):
-                output['fail_reason'] = f"Query did not return any data:\n {query}"
-                return output
-                
-            found_versions= {}
-            for v in result.get('data').get('result'):
-                found_versions[v.get('metric').get('version')] = v.get('value')[1]
-            output['result']['found_versions'] = found_versions
-            output['success'] = True
+            if GlobalAttrs.env_connection_method == 'pod_portForward':
+                result = self.run_query(query)
+                if not result.get('status') == 'success':
+                    output['fail_reason'] = f"could not get metric value:\n {query}"
+                    return output
+
+                if not result.get('data').get('result'):
+                    output['fail_reason'] = f"Query did not return any data:\n {query}"
+                    return output
+
+                found_versions= {}
+                for v in result.get('data').get('result'):
+                    found_versions[v.get('metric').get('version')] = v.get('value')[1]
+                output['result']['found_versions'] = found_versions
+                output['success'] = True
+
+            elif GlobalAttrs.env_connection_method == 'prometheus_endpoint':
+                result = self.run_query(query)
+                if not result.get('status') == 'success':
+                    output['fail_reason'] = f"could not get metric value:\n {query}"
+                    return output
+
+                if not result.get('data').get('result'):
+                    output['fail_reason'] = f"Query did not return any data:\n {query}"
+                    return output
+
+                found_versions= {}
+                for v in result.get('data').get('result'):
+                    found_versions[v.get('metric').get('version')] = v.get('value')[1]
+                output['result']['found_versions'] = found_versions
+                output['success'] = True
 
         except(KeyError, AttributeError) as e:
             output['success']: False
@@ -185,7 +434,7 @@ def verifyKubernetesExporter(self):
             if not result.get('data').get('result'):
                 output['fail_reason'] = f"Query did not return any data:\n {query}"
                 return output
-                
+
             found_versions= {}
             for v in result.get('data').get('result'):
                 found_versions[v.get('metric').get('git_version')] = v.get('value')[1]
@@ -199,45 +448,49 @@ def verifyKubernetesExporter(self):
         return output
 
     def verify_exporters(self):
-        
+
         # Verify node_exporter
         # Check build info
         # Needed results
         # - avaialable not not
         # - version
 
-        print("")        
+
+        # if GlobalAttrs.env_connection_method == 'pod_portForward':
+            # print(self.run_query_pod_portForward('machine_cpu_cores{instance="ip-10-129-184-213.eu-west-1.compute.internal"}'))
+
+        print("")
         rich.print("[underline]Verifying Prometheus connection:[/underline] ...                    ", end="\r")
         prometheus_connection = self.verify_prometheus_connection()
         if prometheus_connection['connected']:
             rich.print("[underline]Verifying Prometheus connection:[/underline] [bold green]Connected                     ")
             rich.print_json(data=prometheus_connection)
+
+            print("")
+            rich.print("[underline]Verifying Prometheus Exporters:[/underline]")
+            print("")
+            rich.print("* Node Exporter:  ...               ", end="\r")
+            verify_node_exporter = self.verifyNodeExporter()
+            if verify_node_exporter.get('success'):
+                rich.print("* Node Exporter:  [bold green]Found           ", end="\r")
+            else:
+                rich.print("* Node Exporter:  [bold red]Not Found           ", end="\r")
+            print("")
+            rich.print_json(data=verify_node_exporter)
+            print("")
+            rich.print("* Kubernetes Exporter: ...         ", end="\r")
+            verify_kubernetes_exporter = self.verifyKubernetesExporter()
+            if verify_kubernetes_exporter.get('success'):
+                rich.print("* Kubernetes Exporter:  [bold green]Found           ", end="\r")
+            else:
+                rich.print("* Kubernetes Exporter:  [bold green]Not Found           ", end="\r")
+            print("")
+            rich.print_json(data=verify_kubernetes_exporter)
+            print(" ")
+
         else:
             rich.print("[underline]Verifying Prometheus connection:[/underline] [bold red]Unable to connect                     ")
             rich.print_json(data=prometheus_connection)
-            exit(1)
-        
-        print("")
-        rich.print("[underline]Verifying Prometheus Exporters:[/underline]")
-        print("")
-        rich.print("* Node Exporter:  ...               ", end="\r")
-        verify_node_exporter = self.verifyNodeExporter()
-        if verify_node_exporter.get('success'):
-            rich.print("* Node Exporter:  [bold green]Found           ", end="\r")
-        else:
-            rich.print("* Node Exporter:  [bold red]Not Found           ", end="\r")
-        print("")
-        rich.print_json(data=verify_node_exporter)
-        print("")
-        rich.print("* Kubernetes Exporter: ...         ", end="\r")
-        verify_kubernetes_exporter = self.verifyKubernetesExporter()
-        if verify_kubernetes_exporter.get('success'):
-            rich.print("* Kubernetes Exporter:  [bold green]Found           ", end="\r")
-        else:
-            rich.print("* Kubernetes Exporter:  [bold green]Not Found           ", end="\r")
-        print("")
-        rich.print_json(data=verify_kubernetes_exporter)
-        print(" ")
 
 
     def check_metrics(self):
@@ -310,7 +563,7 @@ def check_metrics(self):
                 TimeElapsedColumn(),
                 TimeRemainingColumn(),
                 TextColumn("[progress.description]{task.description}"),
-                BarColumn(bar_width=30), 
+                BarColumn(bar_width=30),
                 TaskProgressColumn(),
                 TextColumn("{task.fields[status]}"),
             )
@@ -370,13 +623,3 @@ def check_metrics(self):
         out = tabulate(table, headers='firstrow', tablefmt='grid', showindex=False)
         print(out)
         exit(1)
-
-
-
-
-
-
-
-
-
-
diff --git a/setup.py b/setup.py
index 528d8e9..15ce199 100644
--- a/setup.py
+++ b/setup.py
@@ -8,7 +8,7 @@
 
 setup(
     name = 'kptop',
-    version = '0.0.6',
+    version = '0.0.10',
     author = 'Eslam Gomaa',
     # license = '<the license you chose>',
     description = 'A CLI tool that provides Monitoring for Kubernetes resources on the terminal through Prometheus metircs',


Test patch:
diff --git a/examples/dashboards/test.yml b/examples/dashboards/test.yml
new file mode 100644
index 0000000..31be9f7
--- /dev/null
+++ b/examples/dashboards/test.yml
@@ -0,0 +1,218 @@
+dashboard:
+  name: Kafka cluster
+  description: Staging Kafka dashboard
+  layout:
+    splitMode: row # row
+    fullScreen: true
+    header:
+      enable: false
+      size: 3
+      ratio: 1
+    body:
+      boxes:
+        left:
+          enable: true
+          size: 200
+          ratio: 1
+          split_mode: column
+          split:
+            left_a:
+              size: 25
+              ratio: 1
+            left_b:
+              size: 25
+              ratio: 1
+            left_c:
+              size: 0
+              ratio: 1
+            # left_d:
+            #   size: 0
+            #   ratio: 1
+        middle:
+          enable: false
+          size: 0
+          ratio: 1
+          split_mode: column
+          split:
+            middle_a:
+              size: 0
+              ratio: 1
+            middle_b:
+              size: 0
+              ratio: 1
+            middle_c:
+              size: 0
+              ratio: 1
+        right:
+          enable: true
+          size: 0
+          ratio: 1
+          split_mode: column
+          split:
+            right_a:
+              size: 0
+              ratio: 1
+            right_b:
+              size: 0
+              ratio: 1
+
+  # defaultDataSource:
+  #   type: prometheus
+  #   endpoint: ""
+  #   secure: false
+  #   basicAuthEnabled: false
+  #   basicAuthUserNameVariable: ""
+  #   basicAuthPasswordVariable: ""
+
+  variables:
+    - name: topic
+      default: .*
+      cliArgument:
+        enable: true
+        short: -t
+        required: true
+        description: "Kafka Topic Name"
+    - name: namespace
+      default: .*
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+    - name: kafka-topics-namespace
+      default: kafka-resources
+      cliArgument:
+        enable: true
+        short: -tn
+        required: false
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+
+  visualization:
+    - name: Kafka Data In per second.
+      box: right_a
+      enable: true
+      type: asciiGraph # || progressBar || asciiText || markdown || markdown Table ||Table
+      metricUnit: kb # byte_to_kb_mb_gb_tb # dynamic_byte_convert
+      metric: >
+        sort_desc(sum(irate(kafka_server_brokertopicmetrics_bytesin_total{topic=~"$topic"}[5m])) by (strimzi_io_cluster, topic)) / 1024
+      custom_key: "🍅 {{topic}}"
+      asciiGraphOptions:
+        height: 0
+        width: 80
+        maxHeight: 17
+        maxWidth: 45
+        updateIntervalSeconds: 2
+      historyData:
+        enable: true
+        time: 5m
+
+    - name: Kafka Data Out per second.
+      enable: true
+      box: right_b
+      type: asciiGraph # || progressBarList || asciiText
+      metricUnit: kb
+      metric: >
+        sort_desc(sum(irate(kafka_server_brokertopicmetrics_bytesout_total{topic=~"$topic"}[5m])) by (strimzi_io_cluster, topic)) / 1024
+      custom_key: "🥕 {{topic}}"
+      asciiGraphOptions:
+        height: 0
+        width: 80
+        maxHeight: 17
+        maxWidth: 45
+        updateIntervalSeconds: 2
+        # historyData:
+        #   enable: true
+        #   time: 5m
+
+    - name: Kafka pods memory usage (Sorted by higher memory usage)
+      enable: true
+      box: left_a
+      type: progressBarList
+      metricUnit: mb
+      metrics:
+        total_value_metric: |
+          # Memory limits
+          sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+        usage_value_metric: |
+          # memory usage sorted by higher usage
+          sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+      custom_key: "{{pod}}"
+      progressBarListOptions:
+        maxItemsCount: 10
+        lineBreak: true
+        showBarPercentage: true
+        barWidth: 25
+        updateIntervalSeconds: 5
+
+    - name: Kafka Pods memory usage (simpleTable example)
+      enable: true
+      box: left_b
+      type: simpleTable
+      metricUnit: byte
+      metric: |
+        sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, namespace, karpenter_sh_capacity_type, topology_kubernetes_io_zone,node_kubernetes_io_instance_type)
+      # custom_key: |
+      #   f"{labels['pod']}"
+      simpleTableOptions:
+        tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+        showValue: true
+        headersUppercase: true
+        autoConvertValue: true
+        showTableIndex: true
+        updateIntervalSeconds: 5
+    - name: Kafka pods details (advancedTable example)
+      enable: true
+      box: left_c
+      type: advancedTable
+      advancedTableColumns:
+        - memory usage:
+          metric: |
+            sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+        - memory usage %:
+          metric: |
+            sort_desc(
+              (
+                sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+                /
+                sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+              ) * 100
+            )
+          metricUnit: percentage
+        - memory limit:
+          metric: |
+            sort_desc(sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+        - memory cache:
+          metric: |
+            sort_desc(sum(container_memory_cache{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+        - memory swap:
+          metric: |
+            sum(container_memory_swap{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+          metricUnit: byte
+          autoConvertValdue: true
+        # - file descriptors:
+        #   metric: |
+        #     sort_desc(sum(container_file_descriptors{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        #   metricUnit: None
+        - up time:
+          metric: |
+            sum(time() - kube_pod_start_time{namespace="$namespace", pod=~"$pod"}) by (pod)
+          metricUnit: seconds
+        - AWS AZ:
+          metric: |
+            sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+          valueFromLabel: topology_ebs_csi_aws_com_zone
+      custom_key: "{{pod}}" # "{{pod}} - {{topology_ebs_csi_aws_com_zone}}"
+      advancedTableOptions:
+        tableType: grid # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+        headersUppercase: true
+        autoConvertValue: true
+        showTableIndex: true
+        updateIntervalSeconds: 3
diff --git a/kubePtop/tests.to.delete/command.yaml b/kubePtop/tests.to.delete/command.yaml
new file mode 100644
index 0000000..7696a6b
--- /dev/null
+++ b/kubePtop/tests.to.delete/command.yaml
@@ -0,0 +1,66 @@
+command:
+  name: Pods Info
+  description: Kubernetes Pods info of a specific namespace
+
+  variables:
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+    - name: namespace
+      default: default
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+
+  execute:
+    type: advancedTable
+    columns:
+      - memory usage:
+        metric: |
+          sort_desc(sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory usage %:
+        metric: |
+          sort_desc(
+            (
+              sum(container_memory_usage_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+              /
+              sum(container_spec_memory_limit_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+            ) * 100
+          )
+        metricUnit: percentage
+      - memory limit:
+        metric: |
+          sort_desc(sum(container_spec_memory_limit_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory cache:
+        metric: |
+          sort_desc(sum(container_memory_cache{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory swap:
+        metric: |
+          sum(container_memory_swap{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+        metricUnit: byte
+      - memory max usage:
+        metric: |
+          sum(container_memory_max_usage_bytes{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+        metricUnit: byte
+      - file descriptors:
+        metric: |
+          sort_desc(sum(container_file_descriptors{namespace=~"$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: counter
+      - up time:
+        metric: |
+          sum(time() - kube_pod_start_time{namespace=~"$namespace", pod=~"$pod"}) by (pod)
+        metricUnit: seconds
+    custom_key: "{{pod}}" # "{{pod}} - {{topology_ebs_csi_aws_com_zone}}"
+    advancedTableOptions:
+      tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+      headersUppercase: true
+      autoConvertValue: true
+      showTableIndex: false
+      updateIntervalSeconds: 3
diff --git a/kubePtop/tests.to.delete/command2.yaml b/kubePtop/tests.to.delete/command2.yaml
new file mode 100644
index 0000000..a36118e
--- /dev/null
+++ b/kubePtop/tests.to.delete/command2.yaml
@@ -0,0 +1,74 @@
+command:
+  name: Pods Info
+  description: Kubernetes Pods info of a specific namespace
+
+  # variables:
+  # - name: topic
+  #   default: .*
+  #   cliArgument:
+  #     enable: true
+  #     short: -T
+  #     required: true
+
+  variables:
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+    - name: namespace
+      default: default
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+
+  execute:
+    type: advancedTable
+    columns:
+      - memory usage:
+        metric: |
+          sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory usage %:
+        metric: |
+          sort_desc(
+            (
+              sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+              /
+              sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+            ) * 100
+          )
+        metricUnit: percentage
+      - memory limit:
+        metric: |
+          sort_desc(sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory cache:
+        metric: |
+          sort_desc(sum(container_memory_cache{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: byte
+      - memory swap:
+        metric: |
+          sum(container_memory_swap{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+        metricUnit: byte
+      - memory max usage:
+        metric: |
+          sum(container_memory_max_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+        metricUnit: byte
+      - file descriptors:
+        metric: |
+          sort_desc(sum(container_file_descriptors{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        metricUnit: counter
+      - up time:
+        metric: |
+          sum(time() - kube_pod_start_time{namespace="$namespace", pod=~"$pod"}) by (pod)
+        metricUnit: seconds
+    custom_key: "{{pod}}" # "{{pod}} - {{topology_ebs_csi_aws_com_zone}}"
+    advancedTableOptions:
+      tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+      headersUppercase: true
+      autoConvertValue: true
+      showTableIndex: false
+      updateIntervalSeconds: 3
diff --git a/kubePtop/tests.to.delete/dashboard.yaml b/kubePtop/tests.to.delete/dashboard.yaml
new file mode 100644
index 0000000..31be9f7
--- /dev/null
+++ b/kubePtop/tests.to.delete/dashboard.yaml
@@ -0,0 +1,218 @@
+dashboard:
+  name: Kafka cluster
+  description: Staging Kafka dashboard
+  layout:
+    splitMode: row # row
+    fullScreen: true
+    header:
+      enable: false
+      size: 3
+      ratio: 1
+    body:
+      boxes:
+        left:
+          enable: true
+          size: 200
+          ratio: 1
+          split_mode: column
+          split:
+            left_a:
+              size: 25
+              ratio: 1
+            left_b:
+              size: 25
+              ratio: 1
+            left_c:
+              size: 0
+              ratio: 1
+            # left_d:
+            #   size: 0
+            #   ratio: 1
+        middle:
+          enable: false
+          size: 0
+          ratio: 1
+          split_mode: column
+          split:
+            middle_a:
+              size: 0
+              ratio: 1
+            middle_b:
+              size: 0
+              ratio: 1
+            middle_c:
+              size: 0
+              ratio: 1
+        right:
+          enable: true
+          size: 0
+          ratio: 1
+          split_mode: column
+          split:
+            right_a:
+              size: 0
+              ratio: 1
+            right_b:
+              size: 0
+              ratio: 1
+
+  # defaultDataSource:
+  #   type: prometheus
+  #   endpoint: ""
+  #   secure: false
+  #   basicAuthEnabled: false
+  #   basicAuthUserNameVariable: ""
+  #   basicAuthPasswordVariable: ""
+
+  variables:
+    - name: topic
+      default: .*
+      cliArgument:
+        enable: true
+        short: -t
+        required: true
+        description: "Kafka Topic Name"
+    - name: namespace
+      default: .*
+      cliArgument:
+        enable: true
+        short: -n
+        required: false
+    - name: kafka-topics-namespace
+      default: kafka-resources
+      cliArgument:
+        enable: true
+        short: -tn
+        required: false
+    - name: pod
+      default: .*
+      cliArgument:
+        enable: true
+        short: -po
+        required: false
+
+  visualization:
+    - name: Kafka Data In per second.
+      box: right_a
+      enable: true
+      type: asciiGraph # || progressBar || asciiText || markdown || markdown Table ||Table
+      metricUnit: kb # byte_to_kb_mb_gb_tb # dynamic_byte_convert
+      metric: >
+        sort_desc(sum(irate(kafka_server_brokertopicmetrics_bytesin_total{topic=~"$topic"}[5m])) by (strimzi_io_cluster, topic)) / 1024
+      custom_key: "🍅 {{topic}}"
+      asciiGraphOptions:
+        height: 0
+        width: 80
+        maxHeight: 17
+        maxWidth: 45
+        updateIntervalSeconds: 2
+      historyData:
+        enable: true
+        time: 5m
+
+    - name: Kafka Data Out per second.
+      enable: true
+      box: right_b
+      type: asciiGraph # || progressBarList || asciiText
+      metricUnit: kb
+      metric: >
+        sort_desc(sum(irate(kafka_server_brokertopicmetrics_bytesout_total{topic=~"$topic"}[5m])) by (strimzi_io_cluster, topic)) / 1024
+      custom_key: "🥕 {{topic}}"
+      asciiGraphOptions:
+        height: 0
+        width: 80
+        maxHeight: 17
+        maxWidth: 45
+        updateIntervalSeconds: 2
+        # historyData:
+        #   enable: true
+        #   time: 5m
+
+    - name: Kafka pods memory usage (Sorted by higher memory usage)
+      enable: true
+      box: left_a
+      type: progressBarList
+      metricUnit: mb
+      metrics:
+        total_value_metric: |
+          # Memory limits
+          sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+        usage_value_metric: |
+          # memory usage sorted by higher usage
+          sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+      custom_key: "{{pod}}"
+      progressBarListOptions:
+        maxItemsCount: 10
+        lineBreak: true
+        showBarPercentage: true
+        barWidth: 25
+        updateIntervalSeconds: 5
+
+    - name: Kafka Pods memory usage (simpleTable example)
+      enable: true
+      box: left_b
+      type: simpleTable
+      metricUnit: byte
+      metric: |
+        sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, namespace, karpenter_sh_capacity_type, topology_kubernetes_io_zone,node_kubernetes_io_instance_type)
+      # custom_key: |
+      #   f"{labels['pod']}"
+      simpleTableOptions:
+        tableType: plain # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+        showValue: true
+        headersUppercase: true
+        autoConvertValue: true
+        showTableIndex: true
+        updateIntervalSeconds: 5
+    - name: Kafka pods details (advancedTable example)
+      enable: true
+      box: left_c
+      type: advancedTable
+      advancedTableColumns:
+        - memory usage:
+          metric: |
+            sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+        - memory usage %:
+          metric: |
+            sort_desc(
+              (
+                sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+                /
+                sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+              ) * 100
+            )
+          metricUnit: percentage
+        - memory limit:
+          metric: |
+            sort_desc(sum(container_spec_memory_limit_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+        - memory cache:
+          metric: |
+            sort_desc(sum(container_memory_cache{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+        - memory swap:
+          metric: |
+            sum(container_memory_swap{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone)
+          metricUnit: byte
+          autoConvertValdue: true
+        # - file descriptors:
+        #   metric: |
+        #     sort_desc(sum(container_file_descriptors{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+        #   metricUnit: None
+        - up time:
+          metric: |
+            sum(time() - kube_pod_start_time{namespace="$namespace", pod=~"$pod"}) by (pod)
+          metricUnit: seconds
+        - AWS AZ:
+          metric: |
+            sort_desc(sum(container_memory_usage_bytes{namespace="$namespace", pod=~"$pod"}) by (pod, topology_ebs_csi_aws_com_zone))
+          metricUnit: byte
+          valueFromLabel: topology_ebs_csi_aws_com_zone
+      custom_key: "{{pod}}" # "{{pod}} - {{topology_ebs_csi_aws_com_zone}}"
+      advancedTableOptions:
+        tableType: grid # https://github.com/astanin/python-tabulate?tab=readme-ov-file#table-format
+        headersUppercase: true
+        autoConvertValue: true
+        showTableIndex: true
+        updateIntervalSeconds: 3
diff --git a/kubePtop/tests.to.delete/data_types.py b/kubePtop/tests.to.delete/data_types.py
new file mode 100644
index 0000000..63141c3
--- /dev/null
+++ b/kubePtop/tests.to.delete/data_types.py
@@ -0,0 +1,4 @@
+class dataTypes:
+
+    def __init__(self) -> None:
+        pass
diff --git a/kubePtop/tests.to.delete/test.py b/kubePtop/tests.to.delete/test.py
new file mode 100644
index 0000000..9927719
--- /dev/null
+++ b/kubePtop/tests.to.delete/test.py
@@ -0,0 +1,55 @@
+"""
+Demonstrates how to display a tree of files / directories with the Tree renderable.
+"""
+
+import os
+import pathlib
+import sys
+
+from rich import print
+from rich.filesize import decimal
+from rich.markup import escape
+from rich.text import Text
+from rich.tree import Tree
+
+
+def walk_directory(directory: pathlib.Path, tree: Tree) -> None:
+    """Recursively build a Tree with directory contents."""
+    # Sort dirs first then by filename
+    paths = sorted(
+        pathlib.Path(directory).iterdir(),
+        key=lambda path: (path.is_file(), path.name.lower()),
+    )
+    for path in paths:
+        # Remove hidden files
+        if path.name.startswith("."):
+            continue
+        if path.is_dir():
+            style = "dim" if path.name.startswith("__") else ""
+            branch = tree.add(
+                f"[bold magenta]:open_file_folder: [link file://{path}]{escape(path.name)}",
+                style=style,
+                guide_style=style,
+            )
+            walk_directory(path, branch)
+        else:
+            text_filename = Text(path.name, "green")
+            text_filename.highlight_regex(r"\..*$", "bold red")
+            text_filename.stylize(f"link file://{path}")
+            file_size = path.stat().st_size
+            text_filename.append(f" ({decimal(file_size)})", "blue")
+            icon = "🐍 " if path.suffix == ".py" else "📄 "
+            tree.add(Text(icon) + text_filename)
+
+
+try:
+    directory = os.path.abspath(sys.argv[1])
+except IndexError:
+    print("[b]Usage:[/] python tree.py <DIRECTORY>")
+else:
+    tree = Tree(
+        f":open_file_folder: [link file://{directory}]{directory}",
+        guide_style="bold bright_blue",
+    )
+    walk_directory(pathlib.Path(directory), tree)
+    print(tree)
diff --git a/kubePtop/tests.to.delete/test2.py b/kubePtop/tests.to.delete/test2.py
new file mode 100644
index 0000000..45c1296
--- /dev/null
+++ b/kubePtop/tests.to.delete/test2.py
@@ -0,0 +1,29 @@
+
+from termgraph import termgraph as tg
+import numpy as np
+
+# بيانات الرسم البياني
+labels = ['2017', '2018', '2019', '2020', '2021']
+data = [[3, 4, 9, 16, 25]]
+
+# إعدادات الرسم البياني
+args = {
+    'filename': '',
+    'title': 'Sample ASCII Plot',
+    'width': 50,
+    'format': '{:<5.1f}',
+    'suffix': '',
+    'no_labels': False,
+    'color': None,
+    'vertical': False,
+    'stacked': False,
+    'different_scale': False,
+    'calendar': False,
+    'start_dt': None,
+    'custom_tick': '',
+    'delim': '',
+    'verbose': False
+}
+
+# رسم الرسم البياني
+tg.Chart(colors=['red', 'blue'], labels=labels, data=data, args=args).draw()
diff --git a/kubePtop/tests.to.delete/test3.py b/kubePtop/tests.to.delete/test3.py
new file mode 100644
index 0000000..824c49d
--- /dev/null
+++ b/kubePtop/tests.to.delete/test3.py
@@ -0,0 +1,7 @@
+
+from termgraph import termgraph as tg
+
+labels = ['A', 'B', 'C', 'D']
+data = [[3, 5, 9, 6]]
+
+tg.chart(colors=['blue'], labels=labels, data=data)