diff --git a/README.md b/README.md
old mode 100644
new mode 100755
index bf66bb5c6..f7fb4dc29
--- a/README.md
+++ b/README.md
@@ -1,114 +1,77 @@
-# configng
-This is a refactoring of [armbian-config](https://github.com/armbian/config) using [Bash Utility](https://labbots.github.io/bash-utility)
-embedded in this project. This allows for functional programming in Bash. Error handling and validation are also included.
-The idea is to provide an API in Bash that can be called from a Command line interface, Text User interface and others.
-Why Bash? Well, because it's going to be in every distribution. Striped down distributions
-may not include Python, C/C++, etc. build/runtime environments
-## Quick start
-* `sudo apt install git`
-* `cd ~/`
-* `git clone https://github.com/armbian/configng.git`
-* `bash ~/configng/config.sh`
-
-#### If all goes well you should see list or avalible commands
-```
-Usage: config [ -h | foo ]
-
-Options:
- -h) Print this help.
-
- foo) Usage: config foo [ desk_setup::options ][ io::options ][ boardled::options ][ cpu::options ][ extra_drive::options ][ benchymark::options ]::
-
- desk_setup::options
- see_desktops Display a list of avalible desktops to install.
+
+
+
+ Armbian ConfigNG
+
+
+
- io::options
- set_ir_toggle [ enable ][ disable ] Infrared Remote Control.
-
- boardled::options
- see_sysled See a list of board led options.
- see_sysled_none Set board led options to none (off).
- see_sysled_cpu Set board led options to monitor CPU.
- see_sysled_beat Set board led options to heartbeat pulse.
+# User guide
+## Quick start
+Run the following commands:
+
+ sudo apt install git
+ cd ~/
+ git clone https://github.com/armbian/configng.git
+ cd configng
+ ./bin/armbian-configng --dev
+
+If all goes well you should see the Text-Based User Inerface (TUI)
+
+### To see a list of all functions and their descriptions, run the following command:
+~~~
+bash ~/configng/bin/armbian-configng -h
+~~~
+## Coding Style
+follow the following coding style:
+~~~
+# @description A short description of the function.
+#
+# @exitcode 0 If successful.
+#
+# @options A description if there are options.
+function group::string() {s
+ echo "hello world"
+ return 0
+}
+~~~
+## Codestyle can be used to auto generate
+ - [Markdown](share/armbian-configng/readme.md)
+ - [JSON](share/armbian-configng/data/armbian-configng.json)
+ - [CSV](share/armbian-configng/data/armbian-configng.csv)
+ - [HTML](share/armbian-configng/armbian-configng-table.html)
+ - [github.io](//tearran/github.io/armbian-configng/index.html)
+## Functions list as of 2023-12-05
+## network
+System and Security
- cpu::options
- see_policy Return policy as int based on original armbian-config logic.
- see_freqs Return CPU frequencies as string delimited by space.
- see_min_freq Return CPU minimum frequency as string.
- see_max_freq Return CPU maximum frequency as string.
- see_governor Return CPU governor as string.
- see_governors Return CPU avalible governors as string delimited by space.
- set_freq ** disabled ** Set min, max and CPU governor.
+### set_wifi.sh
- extra_drive::options
- set_spi_vflash Set up a simulated MTD spi flash for testing.
- rem_spi_vflash Remove tsting simulated MTD spi flash.
+ - **Group Name:** network
+ - **Action Name:** NMTUI
+ - **Options:** none.
+ - **Description:** Network Manager.
- benchymark::options
- see_monitor system boot-up performance statistics.
- see_boot_times system boot-up performance statistics.
+## system
+Network Wired wireless Bluetooth access point
-```
-#### Change the systems led to pulse a hearbeat
-```
- bash ~/configng/bin/config.sh foo boardled::see_sysled_beat
-```
-#### Change the systems led to off show a result in whiptail or dialog if installed
-```
- bash ~/configng/bin/config.sh foo boardled::see_sysled_none | bash ~/configng/bin/jampi-config.sh
-```
-#### See avalible settings sytem led options and current setting in []
-```
- bash ~/configng/bin/config.sh foo boardled::see_sysled
-```
-#### See avalible armbian monitor options
-```
- bash ~/configng/bin/config.sh foo benchymark:see_monitor
-```
+### hello_world.sh
+ - **Group Name:** system
+ - **Action Name:** Hello
+ - **Options:** none
+ - **Description:** Hello System.
-## Coding standards
-[Shell Style Guide](https://google.github.io/styleguide/shellguide.html) has some good ideas,
-but fundementally look at the code in lib:
-```
-# @description Strip characters from the beginning of a string.
-#
-# @example
-# echo "$(string::lstrip "Hello World!" "He")"
-# #Output
-# llo World!
-#
-# @arg $1 string The input string.
-# @arg $2 string The characters you want to strip.
-#
-# @exitcode 0 If successful.
-# @exitcode 2 Function missing arguments.
-#
-# @stdout Returns the modified string.
-string::lstrip() {
-[[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
-printf '%s\n' "${1##$2}"
-}
-```
+### see_monitor.sh
-Functions should follow ~~filename~~::func_name style. Then you can tell just from the name which
-file the function is located in. Return codes should also follow a similar pattern:
-* 0 Successful
-* 1 Not found
-* 2 Function missing arguments
-* 3-255 all other errors
+ - **Group Name:** monitor
+ - **Action Name:** Bencharking
+ - **Options:**
+ - **Description:** Armbian Monitor and Bencharking.
-Validate values:
-```
-# Validate minimum frequency is <= maximum frequency
-[ "$min_freq" -gt "$max_freq" ] && printf "%s: Minimum frequency must be <= maximum frequency\n" "${FUNCNAME[0]}" && return 5
-```
-Return values should use stdout:
-```
-# Return value
-printf '%s\n' "$(cat $file)"
-```
+# Inclueded projects
+- [Bash Utility](https://labbots.github.io/bash-utility)
+- [Armbian config](https://github.com/armbian/config.git)
-Only use sudo when needed and never run as root!
diff --git a/bin/armbian-configng b/bin/armbian-configng
new file mode 100755
index 000000000..2a6c89774
--- /dev/null
+++ b/bin/armbian-configng
@@ -0,0 +1,222 @@
+#!/bin/bash
+
+# This script provides a command-line interface for managing Armbian configuration.
+# It loads libraries of functions from the lib directory and displays them in a menu.
+# The user can select a function to run, or use a text-based user interface (TUI) to navigate the menus.
+# The script also provides a help option and a debug option for developers.
+# The script requires sudo privileges to run some functions.
+# The script uses whiptail or dialog for the TUI, depending on which is available.
+
+#set -x
+#set -e
+
+#
+# Enable Dynamic directory root use home ~/ , /bin , /usr/sbin etc..
+bin="$(dirname "${BASH_SOURCE[0]}")"
+directory="$(cd "$bin/../" && pwd )"
+file_name="$(basename "${BASH_SOURCE[0]}")"
+filename="${file_name%.*}"
+libpath=$(cd "$directory/lib/$filename/" && pwd)
+#sharepath=$(cd "$directory/share/${filename%-dev}/" && pwd)
+
+
+#
+# Consept Distribution Compatibility checks
+check_distro() {
+
+ [[ -f "/usr/bin/${filename%%-*}-config" ]] && distro_config="${filename%%-*}"
+ [[ -f "/etc/${filename%%-*}-release" ]] && distro_release="${filename%%-*}"
+ # if both true then we are good to go
+ [[ -z "$distro_config" ]] || [[ -z "$distro_release" ]] && echo "W: Costum build, Tech support links are missing."
+ [[ -n "$distro_config" ]] && [[ -n "$distro_release" ]] && echo "I: This build seems to be community supported" | ./armbian-interface -o
+ [[ -f "/usr/sbin/${filename%%-*}-config" ]] && distro_config="${filename%%-*}"
+ [[ -f "/etc/${filename%%-*}-release" ]] && distro_release="${filename%%-*}"
+
+}
+
+[[ "$1" == "--dev" ]] && dev=1 && shift 1
+
+#
+# Check if the script is dev version.
+suffix="${file_name##*-}"
+
+if [[ "$suffix" == dev ]]; then
+ dev=1
+ check_distro #| armbian-interface -o
+fi
+
+if [[ "$(id -u)" != "0" ]] && [[ "$dev" == "1" ]] ; then
+
+cat << EOF #| ./armbian-interface -o
+I: Running in UX development mode
+W: Admin functions will not work as expected
+
+EOF
+elif [[ "$(id -u)" == "0" ]] && [[ "$dev" == "1" ]] ; then
+cat << EOF | ./armbian-interface -o
+I: Running in UX development mode
+W: Document files may need Admin privleges to edit/remove
+
+EOF
+
+fi
+
+#
+# Check if the script is being run as root
+# UX Development mode bypasses root check, many functions will not work as expected
+
+if [[ "$(id -u)" != "0" ]] && [[ "$dev" != "1" ]]; then
+ echo -e "E: This tool requires root privileges. Try: \"sudo $filename\"" >&2
+ exit 1
+fi
+
+declare -A dialogue
+
+#
+# Check if whiptail or dialog is installed and set the variable 'dialogue' accordingly.
+# todo add a fallback TUI and GUI
+if command -v whiptail &> /dev/null; then
+ dialogue="whiptail"
+elif command -v dialog &> /dev/null; then
+ dialogue="dialog"
+else
+ echo "TUI not found"
+ echo "Warning: Using fallback TUI"
+ sleep 1
+ clear && generate_read
+fi
+
+source "$libpath/functions.sh"
+source "$libpath/documents.sh"
+for file in "$libpath"/*/*.sh; do
+ source "$file"
+done
+
+#
+# mapfile -t categories < <(ls -d "$libpath"/* )
+mapfile -t categories < <(find "$libpath"/* -type d)
+declare -A functions
+
+for category in "${categories[@]}"; do
+ category_name="${category##*/}"
+
+ category_file="$category/readme.md"
+ if [[ -f "$category_file" ]]; then
+ category_description=$(grep -oP "(?<=# @description ).*" "$category_file")
+ fi
+
+ for file in "$category"/*.sh; do
+ description=""
+ while IFS= read -r line; do
+ if [[ $line =~ ^#\ @description\ (.*)$ ]]; then
+ description="${BASH_REMATCH[1]}"
+ elif [[ $line =~ ^function\ (.*::.*)\(\)\{$ ]]; then
+ # END: be15d9bcejpp
+ function_name="${BASH_REMATCH[1]}"
+ key="$category_name:${file##*/}:${function_name}"
+ functions["$key,function_name"]=$(echo "$function_name" | sed 's/.*:://')
+ functions["$key,group_name"]=$(echo "$function_name" | sed 's/::.*//')
+ functions["$key,description"]=$description
+ elif [[ $line =~ ^#\ @options\ (.*)$ ]]; then
+ functions["$key,options"]="${BASH_REMATCH[1]}"
+ fi
+ done < "$file"
+ functions["$key,category"]=$category_name
+ functions["$key,category_description"]=$category_description
+ done
+done
+
+
+#
+# WIP: Check arguments for no flag options
+# armbian-config --help
+# Change to BASH: /usr/sbin/armbian-config main=System selection=BASH
+handle_no_flag(){
+if [[ "$1" == *"="* ]]; then
+ IFS='=' read -r key value <<< "$1"
+ function_name=$(parse_action "$key" "$value")
+ # Call the function using variable indirection
+ ${function_name}
+elif [[ "$1" == "help"* ]]; then
+ generate_list_cli
+fi
+}
+
+#
+# Check arguments for long flag options
+# Help message related to the functions the back end
+handle_long_flag(){
+ if [[ "$1" == "--help" ]]; then
+ generate_list_run
+ exit 0 ;
+ elif [[ "$1" == "--doc" ]]; then
+ generate_doc
+ exit 0 ;
+ fi
+# WIP:
+ if [ "$1" == "--run" ]; then
+ shift # Shifts the arguments to the left, excluding the first argument ("-r")
+ group_name="$1" # Takes the first argument as the group name
+ shift 1 # Shifts the arguments again to exclude the group name
+
+ function_name=$(parse_action "$group_name" "$1")
+ if [ $? -eq 0 ]; then
+ # Call the function using variable indirection
+ ${function_name}
+ fi
+ elif [ "$1" == "--help" ]; then
+ generate_list_run
+ exit
+ elif [ "$1" == "--test" ]; then
+ check_distro | armbian-interface -o && $1 > /dev/null
+ fi
+
+}
+#
+# Check arguments for short flag options
+# THe interface help message
+handle_short_flag(){
+if [ "$1" == "-h" ]; then
+ generate_help
+ exit 0 ;
+# Generate a text-based user interface
+elif [ "$1" == "-t" ] ; then
+ generate_read ; exit 0 ;
+# Generate all doc files
+elif [ "$1" == "-d" ] ; then
+ generate_doc ; exit 0 ;
+elif [ "$1" == "-j" ] ; then
+ generate_json ; exit 0 ;
+fi
+
+}
+
+case "$1" in
+ *"="*)
+ # Handle the case where $1 contains "="
+ handle_no_flag "$@"
+ ;;
+ *"--"*)
+ # Handle the case where $1 starts with "--"
+ handle_long_flag "$@"
+ ;;
+ *"-"*)
+ # Handle the case where $1 starts with "-"
+ handle_short_flag "$1"
+ ;;
+ *)
+ handle_no_flag "$@"
+ # Handle the case where $1 does not match any of the above patterns
+ # You can add your code here
+ ;;
+esac
+
+if [[ -z "$1" ]] ; then
+ while true; do
+ generate_tui ;
+ if [[ "$?" == "0" ]]; then
+ exit 0
+ fi
+ done
+
+fi
\ No newline at end of file
diff --git a/bin/armbian-interface b/bin/armbian-interface
new file mode 100755
index 000000000..ff095fdc0
--- /dev/null
+++ b/bin/armbian-interface
@@ -0,0 +1,119 @@
+#!/bin/bash
+
+#
+# Copyright (c) 2023 Joseph C Turner
+# All rights reserved.
+#
+# This script.
+# demonstrates the compatibility of multiple interfaces for displaying menus or messages.
+# It uses an array to set the options for all three menus (bash, whiptail, and dialog).
+# The script checks if whiptail or dialog are available on the system and uses them to display the menu in a more user-friendly way.
+# If neither of these programs is available, it falls back to using bash.
+# while both are installed falls back to whiptail to display the menu.
+# The user can override the default program by passing an argument when running the script:
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+## DIRECTORY variable to the absolute path of the script's directory
+directory="$(dirname "$(readlink -f "$0")")"
+filename=$(basename "${BASH_SOURCE[0]}")
+
+## DIALOG variable to the absolute path of the script's directory
+DIALOG="bash"
+[[ -x "$(command -v dialog)" ]] && DIALOG="dialog"
+[[ -x "$(command -v whiptail)" ]] && DIALOG="whiptail"
+
+show_help(){
+
+ echo -e "\nUsage: [command] | ${filename%.*} [ -h | -m | -o ]"
+ echo "Options:"
+ echo " -h, Print this help."
+ echo ""
+ echo " -o, Opens an OK message Box"
+ echo ""
+ echo " -m, Opens an Menu select Box."
+ echo ""
+ echo " -p, Opens Popup message box. "
+ echo ""
+ exit 1;
+ }
+
+show_message(){
+
+ # Read the input from the pipe continuously until there is no more input
+ input=""
+ while read -r line; do
+ input+="$line\n"
+ done
+
+ # Display the "OK" message box with the input data
+ [[ $DIALOG != "bash" ]] && $DIALOG --title "Message Box" --msgbox "$input" 0 0
+ [[ $DIALOG == "bash" ]] && echo -e "$input"
+ [[ $DIALOG == "bash" ]] && read -p "Press [Enter] to continue..." ; echo "" ; exit 1
+
+ }
+
+show_popup(){
+
+
+ input=""
+ while read -r line; do
+ input+="$line\n"
+ done
+
+ [[ $DIALOG != "bash" ]] && $DIALOG --title "Popup Box" --infobox "$input" 0 0
+ [[ $DIALOG == "bash" ]] && echo -e "$input"
+
+ }
+
+show_menu(){
+
+
+ # Get the input and convert it into an array of options
+ inpu_raw=$(cat)
+ # Remove the lines befor -h
+ input=$(echo "$inpu_raw" | sed 's/-\([a-zA-Z]\)/\1/' | grep '^ [a-zA-Z] ' | grep -v '\[')
+ options=()
+ while read -r line; do
+ package=$(echo "$line" | awk '{print $1}')
+ description=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ *//')
+ options+=("$package" "$description")
+ done <<< "$input"
+
+ # Display the menu and get the user's choice
+ [[ $DIALOG != "bash" ]] && choice=$($DIALOG --title "Menu" --menu "Choose an option:" 0 0 9 "${options[@]}" 3>&1 1>&2 2>&3)
+
+ # Check if the user made a choice
+ if [ $? -eq 0 ]; then
+ echo "$choice"
+ else
+ echo "You cancelled."
+ fi
+ }
+
+[[ $1 == "-m" ]] && show_menu ;
+[[ $1 == "-o" ]] && show_message ;
+[[ $1 == "-h" ]] && show_help ;
+[[ $1 == "-p" ]] && show_popup ;
+[[ -z "$@" ]] && show_help ;
diff --git a/bin/config.sh b/bin/config.sh
deleted file mode 100755
index 1c7a2d5fe..000000000
--- a/bin/config.sh
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/bin/bash
-
-#
-# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
-#
-# This file is licensed under the terms of the GNU General Public
-# License version 2. This program is licensed "as is" without any
-# warranty of any kind, whether express or implied.
-#
-#
-
-directory="$(dirname "$(readlink -f "$0")")"
-filename=$(basename "${BASH_SOURCE[0]}")
-
-libpath="$directory/../lib"
-
-if [[ -d "$directory/../lib" ]]; then
- libpath="$directory"/../lib
-# installed option todo change when lib location determined
-#elif [[ ! -d "$directory/../lib" && -d "/usr/lib/bash-utility/" && -d "/usr/lib/config/" ]]; then
-# libpath="/usr/lib"
-else
- echo "Libraries not found"
- exit 0
-fi
-
-# Source the files relative to the script location
-for file in "$libpath"/bash-utility/*; do
- source "$file"
-done
-for file in "$libpath"/config/*; do
- source "$file"
-done
-
-functionarray=()
-funnamearray=()
-catagoryarray=()
-descriptionarray=()
-
-for file in "$libpath"/config/*.sh; do
- mapfile -t temp_functionarray < <(grep -oP '^\w+::\w+' "$file")
- functionarray+=("${temp_functionarray[@]}")
-
- mapfile -t temp_funnamearray < <(grep -oP '^\w+::\w+' "$file" | sed 's/.*:://')
- funnamearray+=("${temp_funnamearray[@]}")
-
- mapfile -t temp_catagoryarray < <(grep -oP '^\w+::\w+' "$file" | sed 's/::.*//')
- catagoryarray+=("${temp_catagoryarray[@]}")
-
- mapfile -t temp_descriptionarray < <(grep -oP '^# @description.*' "$file" | sed 's/^# @description //')
- descriptionarray+=("${temp_descriptionarray[@]}")
-done
-
- see_help_dev(){
- # Extract unique prefixes
- declare -A prefixes
- for i in "${!functionarray[@]}"; do
- prefix="${functionarray[i]%%::*}"
- prefixes["$prefix"]=1
- done
-
- # Construct usage line
- usage=""
- for prefix in "${!prefixes[@]}"; do
- usage+="[ $prefix::options ]"
- done
-
-
-# echo "$usage"
- echo "Usage: ${filename%.*} [ -h | foo ]"
- echo ""
- echo -e "Options:"
- echo -e " -h) Print this help."
- echo -e ""
- echo -e " foo) Usage: ${filename%.*} foo $usage "
- echo ""
-
- # Group options by prefix
- declare -A groups
- for i in "${!functionarray[@]}"; do
- prefix="${functionarray[i]%%::*}"
- suffix="${functionarray[i]#*::}"
- groups["$prefix"]+=$'\t\t'"$suffix\t${descriptionarray[i]}"$'\n'
- done
-
- # Print grouped options
- for group in "${!groups[@]}"; do
- echo -e " $group::options"
- echo -e "${groups[$group]}"
- done
-}
-
-
-# TEST 7
-# check for -h -dev @ $1
-# if -dev check @ $1 remove and shift $1 to check for x
-check_opts() {
- if [ "$1" == "foo" ]; then
- shift # Shifts the arguments to the left, excluding the first argument ("-dev")
- function_name="$1" # Assigns the next argument as the function name
- shift # Shifts the arguments again to exclude the function name
-
- found=false
-
- for ((i=0; i<${#functionarray[@]}; i++)); do
- if [ "$function_name" == "${functionarray[i]}" ]; then
- found=true
- ${functionarray[i]} "$@"
- break
- fi
- done
-
- if [ "$found" == false ]; then
- echo "Invalid function name"
- see_help_dev
- exit 1
-
- fi
-
- elif [[ "$1" == "foo" && "$2" == "cpu::set_freq" ]]; then
- # Disabled till understood.
- echo "cpu::set_freq policy min_freq max_freq performance"
- echo "Disabled durring current testing"
-
- else
- see_help_dev
- fi
-}
-
-check_opts "$@"
diff --git a/bin/jampi-config b/bin/jampi-config
deleted file mode 100755
index f9f64e34b..000000000
--- a/bin/jampi-config
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/bin/bash
-
-#
-# Copyright (c) 2023 Joseph C Turner
-# All rights reserved.
-#
-# This script.
-# demonstrates the compatibility of multiple interfaces for displaying menus or messages.
-# It uses an array to set the options for all three menus (bash, whiptail, and dialog).
-# The script checks if whiptail or dialog are available on the system and uses them to display the menu in a more user-friendly way.
-# If neither of these programs is available, it falls back to using bash.
-# while both are installed falls back to whiptail to display the menu.
-# The user can override the default program by passing an argument when running the script:
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-
-# Comeback to this later
-#
-##DIRECTORY variable to the absolute path of the script's directory
-##directory=$(cd "$(dirname "$0")" && pwd)
-#directory="$(dirname "$(readlink -f "$0")")"
-#filename=$(basename "${BASH_SOURCE[0]}")
-#selfpath="$directory"/"$filename"
-##libpath="${directory}"/"its-lib" #Include these scripts Library
-#libpath="$selfpath"
-#
-#
-#clear
-## Check for the availability of whiptail and dialog command-line programs
-## Set the default program to use for displaying messages
-#( ! command -v whiptail >/dev/null && ! command -v dialog >/dev/null ) && default="bash"
-#( command -v whiptail >/dev/null && ! command -v dialog >/dev/null ) && default="whiptail"
-#( ! command -v whiptail >/dev/null && command -v dialog >/dev/null ) && default="dialog"
-#
-## if both whiptail and dialog change to prefered
-#( command -v whiptail >/dev/null && command -v dialog >/dev/null ) && default="whiptail"
-#
-#
-#[[ "$1" == -b ]] && default="bash"
-#[[ "$1" == -w ]] && default="whiptail"
-#[[ "$1" == -n ]] && default="dialog"
-#
-#[[ "$1" == -m ]] && {
-#export NEWT_COLORS="
-#root=blue,black
-#border=green,black
-#title=green,black
-#roottext=red,black
-#window=red,black
-#textbox=white,black
-#button=black,green
-#compactbutton=white,black
-#listbox=white,black
-#actlistbox=black,white
-#actsellistbox=black,green
-#checkbox=green,black
-#actcheckbox=black,green
-#"
-#}
-#
-## Check the cpu architecture. for later handeling if nessery
-#architecture=$(dpkg --print-architecture)
-#[[ "$architecture" == "armf" ]] && true ;
-#
-##setup menu arrays
-#readarray -t functionarray < <( grep -A1 '^##.*@.*:*' "$libpath" | grep -oP '^\w+\(\)' | sed 's/()//' )
-#readarray -t descriptions < <( grep -e '^##.*@.*' "$libpath" | sed "s|^## *@||g;s| ## *@.*||g;s|.*: *||g" )
-#readarray -t descriptionarray < <( for i in "${!descriptions[@]}" ; do printf "%s\n %s\n" "$i" "${descriptions[i]}" ; done )
-#
-### System@Settings:Advanced Settings (armbian-config)
-#cmd_advance()
-#{
-# sudo armbian-config
-#}
-#
-### System@CPU info:Example from Bash Utility (cpu_test.sh)
-#cmd_cpu_info()
-#{
-# [[ ! -f /usr/sbin/cpu_test_library.sh ]] && cmd_cpu_ls ;
-# [[ -f /usr/sbin/cpu_test_library.sh ]] && shell_command=$(sudo /usr/sbin/cpu_test_library.sh )
-# message_box=$( printf '%s ' "${shell_command[@]}" ) ;
-# see_message
-#}
-#
-#
-### System@CPU info:An example function (lscpu)
-#cmd_cpu_ls()
-#{
-#
-# shell_command="$(lscpu)" ;
-# message_box=$( printf '%s ' "${shell_command[@]}" ) ;
-# see_message
-#}
-#
-### System@Bootup Time:An example function (systemd-analyze time)
-#cmd_boot_time()
-#{
-#
-# shell_command="$(systemd-analyze time)" ;
-# message_box=$( printf '%s ' "${shell_command[@]}" ) ;
-# see_message
-#}
-#
-### System@Login Info :An example function (Login Info)
-#cmd_lslogins()
-#{
-#
-# shell_command="$(lslogins)" ;
-# message_box=$( printf '%s ' "${shell_command[@]}" ) ;
-# see_message
-#}
-#
-#
-## Function to display a message using whiptail, dialog or printf depending on what is available on the system
-#see_message()
-#{
-# # Use if neither whiptail nor dialog are available on the system
-# if [[ "$default" == "bash" ]] || ( ! command -v whiptail >/dev/null && ! command -v dialog >/dev/null ); then
-# # Use printf to display the message
-# printf '%s ' "${shell_command[@]}"
-#
-# # Use as default if whiptail is available
-# elif [[ "$default" == "whiptail" ]] && ( command -v whiptail >/dev/null ); then
-# # Use whiptail to display the message
-# whiptail --backtitle "newt whitail: $architecture" --title "description" --msgbox "${message_box[@]}" 0 0 --clear --scrolltext
-#
-# # Use if dialog is available on the system but not whiptail
-# elif [[ "$default" == "dialog" ]] && ( command -v dialog >/dev/null ); then
-# # Use dialog to display the message
-# dialog --backtitle "ncurses dialog: $architecture" --title "description" --msgbox "${message_box[@]}" 0 0 ; clear
-# fi
-#}
-#
-#see_menu()
-#{
-#
-# if [[ "$default" == "bash" ]]; then
-# PS3="Enter a number: "
-# select i in "${descriptions[@]}" ; do ${functionarray[$REPLY - 1]} ; break ; done
-#
-# elif [[ "$default" == "whiptail" ]]; then
-# OPTION=$(whiptail --backtitle "newt whiptail: $architecture" --title "Config" --menu "Choose your option" 20 80 7 "${descriptionarray[@]}" 3>&1 1>&2 2>&3)
-# [[ -n $OPTION ]] && clear && "${functionarray[$OPTION]}"
-#
-# elif [[ "$default" == "dialog" ]]; then
-# OPTION=$(dialog --backtitle "ncurses dialog: $architecture" --title "Config" --menu "Choose your option" 20 80 7 "${descriptionarray[@]}" 3>&1 1>&2 2>&3)
-# [[ -n $OPTION ]] && clear && "${functionarray[$OPTION]}"
-# fi
-#}
-#
-#see_help(){
-#
-# echo ""
-# echo "Usage: ${filename%.*} [ -h | -b | -n | -w | -d | -dev ]"
-# echo -e "Options:"
-# echo -e " -h Print this help."
-# echo -e " -b GNU bash "
-# echo -e " -n NCURSES dialog "
-# echo -e " -w NEWT whiptail - default colors "
-# echo -e " -m dark mode whiptail "
-# echo -e " -dev Options:"
-# for i in "${!functionarray[@]}"; do
-# printf '\t\t%s\t%s \n' "${functionarray[i]}" "${descriptions[i]}"
-# done
-#
-# }
-#
-#main()
-#{
-# if [[ "$1" == --dev ]] ; then
-# default="bash"
-# local found=false
-# for i in "${!functionarray[@]}"; do
-# if [ "$2" == "${functionarray[i]}" ]; then
-# "${functionarray[i]}"
-# found=true
-# break
-# fi
-# done
-# if ! $found; then
-# see_help
-# exit 0
-# fi
-# elif [[ "$1" == -h ]] ; then
-# see_help
-# else
-# see_menu
-# fi
-#}
-#
-#main "$@"
-
-if command -v whiptail > /dev/null; then
- DIALOG=whiptail
-elif command -v dialog > /dev/null; then
- DIALOG=dialog
-else
- echo "Error: Neither whiptail nor dialog is installed."
- exit 1
-fi
-
-input=$(cat)
-$DIALOG --title "Config Options" --msgbox "$input" 0 0
diff --git a/lib/armbian-configng/documents.sh b/lib/armbian-configng/documents.sh
new file mode 100644
index 000000000..8a319822c
--- /dev/null
+++ b/lib/armbian-configng/documents.sh
@@ -0,0 +1,388 @@
+# This function is used to generate a simple JSON file containing all functions and their descriptions.
+# pthon is more suited to complex arrays this should be handeled during build time
+generate_json() {
+ json_objects=()
+ for key in "${!functions[@]}"; do
+ if [[ $key == *",function_name"* ]]; then
+ function_key="${key%,function_name}"
+ function_name="${functions[$key]}"
+ group_name="${functions["$function_key,group_name"]}"
+ description="${functions["$function_key,description"]}"
+ options="${functions["$function_key,options"]}"
+ category="${functions["$function_key,category"]}"
+ category_description="${functions["$function_key,category_description"]}"
+ json_objects+=("{ \"Function Name\": \"$function_name\", \"Group Name\": \"$group_name\", \"Description\": \"$description\", \"Options\": \"$options\", \"Category\": \"$category\", \"Category Description\": \"$category_description\" }")
+ fi
+ done
+ IFS=','
+ echo "[${json_objects[*]}]" | jq
+}
+
+# This function is used to generate a armbian CPU logo
+generate_svg(){
+
+cat << EOF
+
+EOF
+}
+
+# This function is used to generate a CSV file containing all functions and their descriptions.
+generate_csv() {
+ echo "Function Name,Group Name,Description,Options,Category,Category Description"
+ for key in "${!functions[@]}"; do
+ if [[ $key == *",function_name"* ]]; then
+ function_key="${key%,function_name}"
+ function_name="${functions[$key]}"
+ group_name="${functions["$function_key,group_name"]}"
+ description="${functions["$function_key,description"]}"
+ options="${functions["$function_key,options"]}"
+ category="${functions["$function_key,category"]}"
+ category_description="${functions["$function_key,category_description"]}"
+ echo "$function_name,$group_name,$description,$options,$category,$category_description"
+ fi
+ done
+}
+
+generate_csv_test() {
+ for category in "${categories[@]}"; do
+ echo "Function Name,Group Name,Description,Options,Category,Category Description" > "$category.csv"
+ for key in "${!functions[@]}"; do
+ if [[ $key == *",function_name"* ]]; then
+ function_key="${key%,function_name}"
+ function_name="${functions[$key]}"
+ group_name="${functions["$function_key,group_name"]}"
+ description="${functions["$function_key,description"]}"
+ options="${functions["$function_key,options"]}"
+ category="${functions["$function_key,category"]}"
+ category_description="${functions["$function_key,category_description"]}"
+ if [[ $category == "$category" ]]; then
+ echo "$function_name,$group_name,$description,$options,$category,$category_description" >> "$category.csv"
+ fi
+ fi
+ done
+ done
+}
+
+# This function is used to generate a Single page app.
+generate_html5() {
+
+html5_content='
+
+
+
+
+ Armbian '$(echo "$filename")'
+
+
+
+
+
'$(echo "$filename")'
+
+
+
+
+
+
+
+
+
+
+
+
+'
+
+echo "$html5_content" ;
+
+}
+
+# This function is used to generate tabe html file
+# used to check proper array generation and output.
+generate_html() {
+ html_content='
+
+
+
+
+
+
+
+
+
Function Name
+
Group Name
+
Description
+
Options
+
Category
+
Category Description
+
+
+ '
+ for key in "${!functions[@]}"; do
+ if [[ $key == *",function_name"* ]]; then
+ function_key="${key%,function_name}"
+ function_name="${functions[$key]}"
+ group_name="${functions["$function_key,group_name"]}"
+ description="${functions["$function_key,description"]}"
+ options="${functions["$function_key,options"]}"
+ category="${functions["$function_key,category"]}"
+ category_description="${functions["$function_key,category_description"]}"
+ html_content+="
$function_name
$group_name
$description
$options
$category
$category_description
"
+ fi
+ done
+ html_content+='
+
+
+
+
+ '
+
+ echo "$html_content"
+}
+
+# This function is used to generate the main readme.md file
+generate_markdown() {
+cat << EOF
+
+
+
+
+ Armbian ConfigNG
+
+
+
+
+# User guide
+## Quick start
+Run the following commands:
+
+ sudo apt install git
+ cd ~/
+ git clone https://github.com/armbian/configng.git
+ cd configng
+ ./bin/${file_name%.*} --dev
+
+If all goes well you should see the Text-Based User Inerface (TUI)
+
+### To see a list of all functions and their descriptions, run the following command:
+~~~
+bash ~/configng/bin/armbian-configng -h
+~~~
+## Coding Style
+follow the following coding style:
+~~~
+# @description A short description of the function.
+#
+# @exitcode 0 If successful.
+#
+# @options A description if there are options.
+function group::string() {s
+ echo "hello world"
+ return 0
+}
+~~~
+## Codestyle can be used to auto generate
+ - [Markdown](share/${file_name%.*}/readme.md)
+ - [JSON](share/${file_name%.*}/data/${file_name%.*}.json)
+ - [CSV](share/${file_name%.*}/data/${file_name%.*}.csv)
+ - [HTML](share/${file_name%.*}/${file_name%.*}-table.html)
+ - [github.io](//tearran/github.io/${file_name%.*}/index.html)
+## Functions list as of $(date +%Y-%m-%d)
+EOF
+
+ for category in "${categories[@]}"; do
+ echo "## ${category##*/}"
+ echo "${functions["$key,category_description"]}"
+ echo
+
+ for file in "$category"/*.sh; do
+ echo "### ${file##*/}"
+ echo
+
+ mapfile -t functions_in_file < <(grep -oP '(?<=function\s)\w+::\w+' "$file")
+
+ for function in "${functions_in_file[@]}"; do
+ key="${category##*/}:${file##*/}:${function}"
+ echo " - **Group Name:** ${functions["$key,group_name"]}"
+ echo " - **Action Name:** ${functions["$key,function_name"]}"
+ echo " - **Options:** ${functions["$key,options"]}"
+ echo " - **Description:** ${functions["$key,description"]}"
+ echo
+ done
+ done
+ done
+cat << EOF
+
+# Inclueded projects
+- [Bash Utility](https://labbots.github.io/bash-utility)
+- [Armbian config](https://github.com/armbian/config.git)
+
+EOF
+}
+
+
+# This function is used to generate a extention to help meassage of all functions and their descriptions.
+generate_list_run() {
+ echo "Usage: ${filename%.*} [--run] [option] [action]"
+ # Loop through each category
+ for category in "${categories[@]}"; do
+ # Initialize an empty array to store the group names that have been printed
+ declare -A printed_groups
+
+ # Loop through each file in the category
+ for file in "$category"/*.sh; do
+
+ # Extract functions from the file
+ mapfile -t functions_in_file < <(grep -oP '(?<=function\s)\w+::\w+' "$file")
+
+ # Loop through each function in the file
+ for function in "${functions_in_file[@]}"; do
+ key="${category##*/}:${file##*/}:${function}"
+ group_name=${functions["$key,group_name"]}
+
+ # If the group name has not been printed yet, print it and add it to the array
+ declare -A printed_groups
+ if [[ -z ${printed_groups["$group_name"]} ]]; then
+ echo " $group_name, [action]"
+ printed_groups["$group_name"]=1
+ fi
+
+ echo " ${functions["$key,function_name"]} - ${functions["$key,description"]}"
+ echo
+ done
+ done
+ done
+
+}
+
+# This function is used to generate a no flag options help message
+generate_list_cli() {
+
+ echo "Usage: ${filename%.*} [group]=[function]"
+ # Loop through each category
+ for category in "${categories[@]}"; do
+ # Initialize an empty array to store the group names that have been printed
+ declare -A printed_groups
+
+ # Loop through each file in the category
+ for file in "$category"/*.sh; do
+
+ # Extract functions from the file
+ mapfile -t functions_in_file < <(grep -oP '(?<=function\s)\w+::\w+' "$file")
+
+ # Loop through each function in the file
+ for function in "${functions_in_file[@]}"; do
+ key="${category##*/}:${file##*/}:${function}"
+ group_name=${functions["$key,group_name"]}
+ printf "\t%-20s - \t %s \n" "$group_name=${functions["$key,function_name"]}" "${functions["$key,description"]}"
+ done
+ done
+ done
+}
+
+
+# This function is used to generate a help message.
+generate_help(){
+cat << EOF
+Usage: ${filename%.*} [flag][option]
+ flag options:
+ -h, Print this help.
+ -t, Show a TUI fallback read.
+ --help, Prints Help message of long flag interactive options (WIP)."
+ help, View advanced no-interface options (CURRENT FOCUS)."
+EOF
+}
+
+# THis function is used to make documents
+generate_and_print() {
+ local generate_func=$1
+ local filename=$2
+ local file_extension=$3
+ local output_message=$4
+
+ "$generate_func" > "$filename.$file_extension"
+ chmod 755 "$filename.$file_extension"
+ echo "$output_message - generated $filename.$file_extension"
+}
+
+generate_doc() {
+ dir="$(dirname "$(dirname "$(realpath "$0")")")/share/${filename%-dev}"
+ if [[ ! -d "$dir" ]]; then
+ mkdir -p "$dir/data/"
+ fi
+ cd "$dir" || exit
+ generate_svg > "$filename.svg"
+ generate_and_print generate_markdown "../../readme" md "readme.md"
+ generate_and_print generate_html "../../index" html "index.html"
+ generate_and_print generate_html5 "index" html "HTML5"
+ generate_and_print generate_json "data/$filename" json "JSON"
+ generate_and_print generate_csv "data/${filename%-dev}" csv "CSV"
+ if [[ "$EUID" -eq 0 ]]; then
+ chown -R "$SUDO_USER":"$SUDO_USER" "$(dirname "$dir")"
+ cd ../../
+ chown "$SUDO_USER":"$SUDO_USER" readme.md
+ fi
+ return 0
+}
\ No newline at end of file
diff --git a/lib/armbian-configng/functions.sh b/lib/armbian-configng/functions.sh
new file mode 100644
index 000000000..3d598c61b
--- /dev/null
+++ b/lib/armbian-configng/functions.sh
@@ -0,0 +1,145 @@
+
+
+# This function is used to generate a text-based user interface (TUI) for navigating the menus.
+generate_tui() {
+ local options=()
+ local i=0
+ declare -A categories_array
+ for category in "${categories[@]}"; do
+ local category_name="${category##*/}"
+ local category_description=""
+ local category_file="$category/readme.md"
+
+ if [[ -f "$category_file" ]]; then
+ category_description=$(grep -oP "(?<=# @description ).*" "$category_file")
+ fi
+
+ categories_array["$i"]="$category_name"
+ description_array["$i"]="$category_description"
+ options+=("$i" "$(printf '%-7s - %-8s' "${categories_array[$i]}" "${description_array[$i]}")")
+ #options+=("$i" "${categories_array[$i]} - ${description_array[$i]}")
+ ((++i))
+ done
+ options+=("$i" "$(printf '%-7s - %-8s' "Legacy" "Run Legacy configuration")")
+
+ #options+=("$i" "Legacy - Run Legacy configuration")
+ ((++i))
+ options+=("$i" "$(printf '%-7s - %-8s' "Help" "Documentation, support, sources")")
+ #options+=("$i" "Help - Documentation, support, sources" )
+ ((++i))
+
+ local choice
+
+ choice=$($dialogue --menu "Select a category:" 0 0 9 "${options[@]}" 3>&1 1>&2 2>&3)
+
+ if [[ -n $choice ]]; then
+
+ if ((choice == "$i - 1")); then
+ generate_help | armbian-interface -o
+ exit ;
+ elif ((choice == "$i - 2")); then
+ armbian-config
+ exit ;
+ else
+ generate_sub_tui "${categories_array[$choice]}"
+ fi
+ fi
+}
+
+# This function is used to generate a text-based user interface (TUI) for navigating the menus.
+generate_sub_tui() {
+ local category="$1"
+ local options=()
+ local i=0
+ declare -A functions_array
+ for file in "$libpath/$category"/*.sh; do
+ mapfile -t functions_in_file < <(grep -oP '(?<=function\s)\w+::\w+' "$file")
+ for function in "${functions_in_file[@]}"; do
+ key="${category##*/}:${file##*/}:${function}"
+ functions_array["$i"]="$function"
+ options+=("$i" "${functions["$key,function_name"]} - ${functions["$key,description"]}")
+ ((++i))
+ done
+ done
+
+ local choice
+
+ choice=$($dialogue --menu "Select a function:" 0 0 9 "${options[@]}" 3>&1 1>&2 2>&3)
+
+ if [[ -n $choice ]]; then
+ generate_action "${functions_array[$choice]}"
+ fi
+
+}
+
+# This function is used to generate a whiptail/dialog text-based user interface (TUI) for navigating the menus.
+generate_action() {
+ local function_name="$1"
+ ${function_name}
+}
+
+# This function is used to generate a bash text-based user interface (TUI) for navigating the menus.
+generate_read() {
+ echo
+ echo "Please select an action:"
+ echo
+ # Initialize an empty array to store the function keys
+ declare -a function_keys
+
+ # Loop through each key in the functions array
+ local i=1
+ local current_category=""
+ for key in "${!functions[@]}"; do
+ if [[ $key == *",function_name" ]]; then
+ # Add the key to the function_keys array
+ function_keys[i]="${key%,function_name}"
+
+ # Check if the category has changed and display it if so
+ local category="${functions["${function_keys[i]},category"]}" # < editor"
+ if [[ "$category" != "$current_category" ]]; then
+ echo "Category: $category"
+ current_category="$category"
+ fi
+
+ # Display the function and its description as an option in the menu
+ echo " $i. ${functions["${function_keys[i]},group_name"]} ${functions[$key]} - ${functions["${function_keys[i]},description"]}" #" < for my editor
+ ((i++))
+ fi
+ done
+
+ echo
+ echo "$i. Show help"
+ ((i++))
+ echo "$i. Exit"
+
+ read -p "Enter your choice: " choice
+
+ if ((choice == i-1)); then
+ generate_help
+ elif ((choice == i)); then
+ exit 0
+ elif ((choice >= 1 && choice <= ${#function_keys[@]})); then
+ # Call the selected function using variable indirection
+ eval "${functions["${function_keys[choice]},group_name"]}::${functions["${function_keys[choice]},function_name"]}" #" < for my editor
+ else
+ echo "Invalid choice"
+ fi
+}
+
+# This function is used to parse the action name and return the full function name.
+parse_action() {
+ local group=$1
+ local action=$2
+
+ # Construct the full function name
+ local function_name="${group}::${action}"
+
+ # Check if the function exists
+ if declare -f "$function_name" > /dev/null; then
+ # Return the function name
+ echo "$function_name"
+ else
+ echo "Error: Unknown action '$action' for group '$group'"
+ return 1
+ fi
+}
\ No newline at end of file
diff --git a/lib/armbian-configng/network/readme.md b/lib/armbian-configng/network/readme.md
new file mode 100644
index 000000000..646eff7e0
--- /dev/null
+++ b/lib/armbian-configng/network/readme.md
@@ -0,0 +1,3 @@
+
+# @description Network Wired wireless Bluetooth access point
+
diff --git a/lib/armbian-configng/network/set_wifi.sh b/lib/armbian-configng/network/set_wifi.sh
new file mode 100644
index 000000000..337a7d899
--- /dev/null
+++ b/lib/armbian-configng/network/set_wifi.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
+#
+# This file is licensed under the terms of the GNU General Public
+# License version 2. This program is licensed "as is" without any
+# warranty of any kind, whether express or implied.
+
+
+
+# @description Network Manager.
+#
+# @exitcode 0 If successful.
+#
+# @options none
+function network::NMTUI(){
+ nmtui connect
+ return 0
+}
diff --git a/lib/armbian-configng/system/hello_world.sh b/lib/armbian-configng/system/hello_world.sh
new file mode 100644
index 000000000..c30f21520
--- /dev/null
+++ b/lib/armbian-configng/system/hello_world.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
+#
+# This file is licensed under the terms of the GNU General Public
+# License version 2. This program is licensed "as is" without any
+# warranty of any kind, whether express or implied.
+
+
+# @description Hello System.
+#
+# @exitcode 0 If successful.
+#
+# @options none.
+#
+function system::Hello(){
+
+ echo "Hello Armbian"
+ return 0
+}
+
diff --git a/lib/armbian-configng/system/readme.md b/lib/armbian-configng/system/readme.md
new file mode 100644
index 000000000..7adee2ea4
--- /dev/null
+++ b/lib/armbian-configng/system/readme.md
@@ -0,0 +1,2 @@
+
+# @description System and Security
diff --git a/lib/armbian-configng/system/see_monitor.sh b/lib/armbian-configng/system/see_monitor.sh
new file mode 100644
index 000000000..da1ef94d7
--- /dev/null
+++ b/lib/armbian-configng/system/see_monitor.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
+#
+# This file is licensed under the terms of the GNU General Public
+# License version 2. This program is licensed "as is" without any
+# warranty of any kind, whether express or implied.
+
+
+# @description Armbian Monitor and Bencharking.
+#
+# @exitcode 0 If successful.
+#
+# @options none
+function monitor::Bencharking(){
+ see_menu #| armbian-interface -o
+ return 0 ;
+}
+
+see_menu(){
+ # Define the script
+ script="$(which armbianmonitor)"
+
+ # Run the script with the -h option and save the output to a variable
+ help_message=$("$script" -h ) || exit 2
+
+ # Reformat the help message into an array line by line
+ readarray -t script_launcher < <(echo "$help_message" | sed 's/-\([a-zA-Z]\)/\1/' | grep '^ [a-zA-Z] ' | grep -v '\[')
+
+ # Loop through each line in the array and create a menu string
+ menu_string=""
+ for line in "${script_launcher[@]}"; do
+ # Append the formatted line to the menu string
+ if [[ "$line" != " d "* ]] && [[ "$line" != " c "* ]]; then
+ menu_string+="$line\n"
+ fi
+ done
+
+ # Use the get_help_msg function and pipe its output into configng-interface -m
+ selected_option=$(echo -e "$menu_string" | armbian-interface -m)
+
+ # Run the armbian-monitor script with the selected option
+ [[ -n "$selected_option" ]] && "$script" -"$selected_option";
+ }
+
diff --git a/lib/bash-utility-master/.editorconfig b/lib/bash-utility-master/.editorconfig
new file mode 100644
index 000000000..f9b075876
--- /dev/null
+++ b/lib/bash-utility-master/.editorconfig
@@ -0,0 +1,22 @@
+# EditorConfig is awesome: https://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+# for shfmt
+[*.sh]
+indent_style = space
+indent_size = 4
+shell_variant = bash
+switch_case_indent = true
+space_redirects = true
+
+[*.md]
+trim_trailing_whitespace = false
\ No newline at end of file
diff --git a/lib/bash-utility-master/.gitignore b/lib/bash-utility-master/.gitignore
new file mode 100644
index 000000000..7c7bf7091
--- /dev/null
+++ b/lib/bash-utility-master/.gitignore
@@ -0,0 +1,3 @@
+/tmp
+gh-pages
+hugo-docs
diff --git a/lib/bash-utility-master/.remarkrc b/lib/bash-utility-master/.remarkrc
new file mode 100644
index 000000000..a3ff1e10d
--- /dev/null
+++ b/lib/bash-utility-master/.remarkrc
@@ -0,0 +1,8 @@
+{
+ "plugins": [
+ "remark-preset-lint-markdown-style-guide",
+ ["remark-lint-list-item-spacing", false],
+ ["remark-lint-maximum-line-length", false],
+ ["remark-lint-no-duplicate-headings", false]
+ ]
+}
diff --git a/lib/bash-utility-master/CODE_OF_CONDUCT.md b/lib/bash-utility-master/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..461c926b9
--- /dev/null
+++ b/lib/bash-utility-master/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+- Using welcoming and inclusive language
+- Being respectful of differing viewpoints and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+- The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+- Trolling, insulting/derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at . All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at
+
+For answers to common questions about this code of conduct, see
+
+
+[homepage]: https://www.contributor-covenant.org
diff --git a/lib/bash-utility-master/CONTRIBUTING.md b/lib/bash-utility-master/CONTRIBUTING.md
new file mode 100644
index 000000000..aa401df88
--- /dev/null
+++ b/lib/bash-utility-master/CONTRIBUTING.md
@@ -0,0 +1,129 @@
+# Contributing to Bash-Utility
+
+:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
+The following is a set of guidelines for contributing to this project on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
+
+## Table of Contents
+- [Code Contributions](#code-contributions)
+- [Code Guidelines](#code-guidelines)
+ - [Styleguide](#styleguide)
+ - [Bashdoc guideline](#bashdoc-guideline)
+- [Documentation](#documentation)
+- [Commit Guidelines](#commit-guidelines)
+- [Pull Request Guidelines](#pull-request-guidelines)
+- [Contact](#contact)
+
+## Code Contributions
+
+Great, the more, the merrier.
+
+Sane code contributions are always welcome, whether to the code or documentation.
+
+Before making a pull request, make sure to follow below guidelines:
+
+### Code Guidelines
+
+#### Styleguide
+
+- Variable names must be meaningful and self-documenting.
+- Long variable names must be structured by underscores to improve legibility.
+- Global variables and constants must be ALL CAPS with underscores. (eg., INPUT_FILE)
+- local variables used within functions must be all lower case with underscores ( only if required ). (eg., input_data)
+- Variable names can be alphanumeric with underscores. No special characters in variable names.
+- Variables name must not start with number.
+- Variables within function must be declared. So the scope of variable is restricted to the function.
+- Avoid accessing global variables within functions.
+- Function names must be all lower case with underscores to seperate words (snake_case).
+- Function name must start with section name followed by 2 colons and then the function name (eg., `array::contains()`)
+- Try using bash builtins and string substitution as much as possible.
+- Use printf everywhere instead of echo.
+- Before adding a new logic, be sure to check the existing code.
+- Make sure to add the function in appropriate section based on its operation.
+- Use [shfmt](https://github.com/mvdan/sh) to format the script. Use below command:
+
+ ```shell
+ shfmt upload.sh
+ ```
+
+ The repo already provides the .editorconfig file, which shfmt reads, so no need for extra flags.
+ You can also install shfmt for various editors, refer their repo for information.
+ Note: This is strictly necessary to maintain consistency, do not skip.
+
+- Script should pass all [shellcheck](https://www.shellcheck.net/) warnings, if not, then disable the warning and give a valid reason.
+
+#### Bashdoc guideline
+
+The documentation is generated based on the function documentation within the script file. So ensure to follow the style so the documentation is
+properly generated by the generator.
+
+Follow the below bashdoc template to add function introductory comment.
+
+```bash
+# @description Multiline description goes here and
+# there
+#
+# @example
+# sample::function a b c
+# echo 123
+#
+# @arg $1 string Some arg.
+# @arg $2 any Rest of arguments.
+#
+# @noargs
+#
+# @exitcode 0 If successfull.
+# @exitcode >0 On failure
+# @exitcode 5 On some error.
+#
+# @stdout Path to something.
+#
+# @see sample::other_function(()
+sample::function() {
+}
+```
+
+- Each function must have a description detailing what the function does and a sample usage example to show how the function can be used.
+- specify whether the function accepts args or no args by specifying @arg or @noargs tag in the comment.
+- Make sure to document the exitcode emitted by the function.
+- If the function is similar to other function add a reference to function using @see tag.
+
+### Documentation
+
+- Refrain from making unnecessary newlines or whitespace.
+- Use pure markdown as much as possible, html is accepted but shouldn't be a priority.
+- The markdown must pass RemarkLint checks.
+- The function documentation and Table of Content is autogenerated using `generate_readme.sh`. So DO NOT edit them manually. Use the following command to update ToC and Bashdoc.
+
+ ```bash
+ ./bin/generate_readme.sh -f README.md -s src/
+ ```
+
+### Commit Guidelines
+
+It is recommended to use small commits over one large commit. Small, focused commits make the review process easier and are more likely to be accepted.
+
+It is also important to summarise the changes made with brief commit messages. If the commit fixes a specific issue, it is also good to note that in the commit message.
+
+The commit message should start with a single line that briefly describes the changes. That should be followed by a blank line and then a more detailed explanation.
+
+Before committing check for unnecessary whitespace with `git diff --check`.
+
+### Pull Request Guidelines
+
+The following guidelines will increase the likelihood that your pull request will get accepted:
+
+- Follow the commit and code guidelines.
+- Keep the patches on topic and focused.
+- Try to avoid unnecessary formatting and clean-up where reasonable.
+
+A pull request should contain the following:
+
+- At least one commit (all of which should follow the Commit Guidelines).
+- Title that summarises the issue/feature.
+- Description that briefly summarises the changes.
+
+After submitting a pull request, you should get a response within 7 days. If you do not, don't hesitate to ping the thread.
+
+## Contact
+
+For further inquiries, you can contact the developer by opening an issue on the repository.
diff --git a/lib/bash-utility-master/LICENSE b/lib/bash-utility-master/LICENSE
new file mode 100644
index 000000000..99dd0836b
--- /dev/null
+++ b/lib/bash-utility-master/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 labbots
+
+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/lib/bash-utility-master/README.md b/lib/bash-utility-master/README.md
new file mode 100644
index 000000000..9bc1f9484
--- /dev/null
+++ b/lib/bash-utility-master/README.md
@@ -0,0 +1,3026 @@
+
Bash Utility
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Bash library which provides utility functions and helpers for functional programming in Bash.
+
+Detailed documentation is available at
+
+
+
+## Table of Contents
+
+- [Installation](#installation)
+ - [Method 1 - Git Submodules](#method-1---git-submodules)
+ - [Method 2 - Git Clone](#method-2---git-clone)
+ - [Method 3 - Direct Download](#method-3---direct-download)
+- [Usage](#usage)
+- [Array](#array)
+ - [array::contains()](#arraycontains)
+ - [array::dedupe()](#arraydedupe)
+ - [array::is_empty()](#arrayis_empty)
+ - [array::join()](#arrayjoin)
+ - [array::reverse()](#arrayreverse)
+ - [array::random_element()](#arrayrandom_element)
+ - [array::sort()](#arraysort)
+ - [array::rsort()](#arrayrsort)
+ - [array::bsort()](#arraybsort)
+ - [array::merge()](#arraymerge)
+- [Check](#check)
+ - [check::command_exists()](#checkcommand_exists)
+ - [check::is_sudo()](#checkis_sudo)
+- [Collection](#collection)
+ - [collection::each()](#collectioneach)
+ - [collection::every()](#collectionevery)
+ - [collection::filter()](#collectionfilter)
+ - [collection::find()](#collectionfind)
+ - [collection::invoke()](#collectioninvoke)
+ - [collection::map()](#collectionmap)
+ - [collection::reject()](#collectionreject)
+ - [collection::some()](#collectionsome)
+- [Date](#date)
+ - [date::now()](#datenow)
+ - [date::epoc()](#dateepoc)
+ - [date::add_days_from()](#dateadd_days_from)
+ - [date::add_months_from()](#dateadd_months_from)
+ - [date::add_years_from()](#dateadd_years_from)
+ - [date::add_weeks_from()](#dateadd_weeks_from)
+ - [date::add_hours_from()](#dateadd_hours_from)
+ - [date::add_minutes_from()](#dateadd_minutes_from)
+ - [date::add_seconds_from()](#dateadd_seconds_from)
+ - [date::add_days()](#dateadd_days)
+ - [date::add_months()](#dateadd_months)
+ - [date::add_years()](#dateadd_years)
+ - [date::add_weeks()](#dateadd_weeks)
+ - [date::add_hours()](#dateadd_hours)
+ - [date::add_minutes()](#dateadd_minutes)
+ - [date::add_seconds()](#dateadd_seconds)
+ - [date::sub_days_from()](#datesub_days_from)
+ - [date::sub_months_from()](#datesub_months_from)
+ - [date::sub_years_from()](#datesub_years_from)
+ - [date::sub_weeks_from()](#datesub_weeks_from)
+ - [date::sub_hours_from()](#datesub_hours_from)
+ - [date::sub_minutes_from()](#datesub_minutes_from)
+ - [date::sub_seconds_from()](#datesub_seconds_from)
+ - [date::sub_days()](#datesub_days)
+ - [date::sub_months()](#datesub_months)
+ - [date::sub_years()](#datesub_years)
+ - [date::sub_weeks()](#datesub_weeks)
+ - [date::sub_hours()](#datesub_hours)
+ - [date::sub_minutes()](#datesub_minutes)
+ - [date::sub_seconds()](#datesub_seconds)
+ - [date::format()](#dateformat)
+- [Debug](#debug)
+ - [debug::print_array()](#debugprint_array)
+ - [debug::print_ansi()](#debugprint_ansi)
+- [File](#file)
+ - [file::make_temp_file()](#filemake_temp_file)
+ - [file::make_temp_dir()](#filemake_temp_dir)
+ - [file::name()](#filename)
+ - [file::basename()](#filebasename)
+ - [file::extension()](#fileextension)
+ - [file::dirname()](#filedirname)
+ - [file::full_path()](#filefull_path)
+ - [file::mime_type()](#filemime_type)
+ - [file::contains_text()](#filecontains_text)
+- [Format](#format)
+ - [format::human_readable_seconds()](#formathuman_readable_seconds)
+ - [format::bytes_to_human()](#formatbytes_to_human)
+ - [format::strip_ansi()](#formatstrip_ansi)
+ - [format::text_center()](#formattext_center)
+ - [format::report()](#formatreport)
+ - [format::trim_text_to_term()](#formattrim_text_to_term)
+- [Interaction](#interaction)
+ - [interaction::prompt_yes_no()](#interactionprompt_yes_no)
+ - [interaction::prompt_response()](#interactionprompt_response)
+- [Json](#json)
+ - [json::get_value()](#jsonget_value)
+- [Miscellaneous](#miscellaneous)
+ - [misc::check_internet_connection()](#misccheck_internet_connection)
+ - [misc::get_pid()](#miscget_pid)
+ - [misc::get_uid()](#miscget_uid)
+ - [misc::generate_uuid()](#miscgenerate_uuid)
+- [Operating System](#operating-system)
+ - [os::detect_os()](#osdetect_os)
+ - [os::detect_linux_distro()](#osdetect_linux_distro)
+ - [os::detect_linux_version()](#osdetect_linux_version)
+ - [os::detect_mac_version()](#osdetect_mac_version)
+- [String](#string)
+ - [string::trim()](#stringtrim)
+ - [string::split()](#stringsplit)
+ - [string::lstrip()](#stringlstrip)
+ - [string::rstrip()](#stringrstrip)
+ - [string::to_lower()](#stringto_lower)
+ - [string::to_upper()](#stringto_upper)
+ - [string::contains()](#stringcontains)
+ - [string::starts_with()](#stringstarts_with)
+ - [string::ends_with()](#stringends_with)
+ - [string::regex()](#stringregex)
+- [Terminal](#terminal)
+ - [terminal::is_term()](#terminalis_term)
+ - [terminal::detect_profile()](#terminaldetect_profile)
+ - [terminal::clear_line()](#terminalclear_line)
+- [Validation](#validation)
+ - [validation::email()](#validationemail)
+ - [validation::ipv4()](#validationipv4)
+ - [validation::ipv6()](#validationipv6)
+ - [validation::alpha()](#validationalpha)
+ - [validation::alpha_num()](#validationalpha_num)
+ - [validation::alpha_dash()](#validationalpha_dash)
+ - [validation::version_comparison()](#validationversion_comparison)
+- [Variable](#variable)
+ - [variable::is_array()](#variableis_array)
+ - [variable::is_numeric()](#variableis_numeric)
+ - [variable::is_int()](#variableis_int)
+ - [variable::is_float()](#variableis_float)
+ - [variable::is_bool()](#variableis_bool)
+ - [variable::is_true()](#variableis_true)
+ - [variable::is_false()](#variableis_false)
+ - [variable::is_empty_or_null()](#variableis_empty_or_null)
+- [Inspired By](#inspired-by)
+- [License](#license)
+
+
+## Installation
+The script can be installed and sourced using following methods.
+
+### Method 1 - Git Submodules
+If the library is used inside a git project then git submodules can be used to install the library to the project.
+Following command will initialize git submodule and download the library to `./vendor/bash-utility` folder.
+
+```shell
+git submodule init
+git submodule add -b master https://github.com/labbots/bash-utility vendor/bash-utility
+```
+
+To Update submodules to latest code execute the following command.
+
+```shell
+git submodule update --rebase --remote
+```
+Once the submodule is added or updated, make sure to commit changes to your repository.
+
+```shell
+git add .
+git commit -m 'Added/updated bash-utility library.'
+```
+**Note:** When cloning your repository, use `--recurse-submodules` flag to `git clone` command to install the git sub modules.
+
+### Method 2 - Git Clone
+If you don't want to use git submodules, you can use `git clone` to download library and then move the files to desired location manually.
+
+The below command will clone the repository to `vendor/bash-utility` folder in current working directory.
+
+```shell
+git clone https://github.com/labbots/bash-utility.git ./vendor/bash-utility
+```
+### Method 3 - Direct Download
+If you do not have git installed, you can download the archive of the latest version of the library. Extract the zip file to appropriate folder by following the below command.
+
+```shell
+wget https://github.com/labbots/bash-utility/archive/master.zip
+unzip -q master.zip -d tmp
+mkdir -p vendor/bash-utility
+mv tmp/bash-utility-master vendor/bash-utility
+rm tmp
+```
+
+## Usage
+Bash utility functions can be used by simply sourcing the library script file to your own script.
+To access all the functions within the bash-utility library, you could import the main bash file as follows.
+
+```shell
+source "vendor/bash-utility/bash-utility.sh"
+```
+
+You can also only use the necessary library functions by only importing the required function files.
+
+```shell
+source "vendor/bash-utility/src/array.sh"
+```
+
+
+
+## Array
+
+Functions for array operations and manipulations.
+
+### array::contains()
+
+Check if item exists in the given array.
+
+#### Arguments
+
+- **$1** (mixed): Item to search (needle).
+- **$2** (array): array to be searched (haystack).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If no match found in the array.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+array=("a" "b" "c")
+array::contains "c" ${array[@]}
+#Output
+0
+```
+
+### array::dedupe()
+
+Remove duplicate items from the array.
+
+#### Arguments
+
+- **$1** (array): Array to be deduped.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- Deduplicated array.
+
+#### Example
+
+```bash
+array=("a" "b" "a" "c")
+printf "%s" "$(array::dedupe ${array[@]})"
+#Output
+a
+b
+c
+```
+
+### array::is_empty()
+
+Check if a given array is empty.
+
+#### Arguments
+
+- **$1** (array): Array to be checked.
+
+#### Exit codes
+
+- **0**: If the given array is empty.
+- **2**: If the given array is not empty.
+
+#### Example
+
+```bash
+array=("a" "b" "c" "d")
+array::is_empty "${array[@]}"
+```
+
+### array::join()
+
+Join array elements with a string.
+
+#### Arguments
+
+- **$1** (string): String to join the array elements (glue).
+- **$2** (array): array to be joined with glue string.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- String containing a string representation of all the array elements in the same order,with the glue string between each element.
+
+#### Example
+
+```bash
+array=("a" "b" "c" "d")
+printf "%s" "$(array::join "," "${array[@]}")"
+#Output
+a,b,c,d
+printf "%s" "$(array::join "" "${array[@]}")"
+#Output
+abcd
+```
+
+### array::reverse()
+
+Return an array with elements in reverse order.
+
+#### Arguments
+
+- **$1** (array): The input array.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- The reversed array.
+
+#### Example
+
+```bash
+array=(1 2 3 4 5)
+printf "%s" "$(array::reverse "${array[@]}")"
+#Output
+5 4 3 2 1
+```
+
+### array::random_element()
+
+Returns a random item from the array.
+
+#### Arguments
+
+- **$1** (array): The input array.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- Random item out of the array.
+
+#### Example
+
+```bash
+array=("a" "b" "c" "d")
+printf "%s\n" "$(array::random_element "${array[@]}")"
+#Output
+c
+```
+
+### array::sort()
+
+Sort an array from lowest to highest.
+
+#### Arguments
+
+- **$1** (array): The input array.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- sorted array.
+
+#### Example
+
+```bash
+sarr=("a c" "a" "d" 2 1 "4 5")
+array::array_sort "${sarr[@]}"
+#Output
+1
+2
+4 5
+a
+a c
+d
+```
+
+### array::rsort()
+
+Sort an array in reverse order (highest to lowest).
+
+#### Arguments
+
+- **$1** (array): The input array.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- reverse sorted array.
+
+#### Example
+
+```bash
+sarr=("a c" "a" "d" 2 1 "4 5")
+array::array_sort "${sarr[@]}"
+#Output
+d
+a c
+a
+4 5
+2
+1
+```
+
+### array::bsort()
+
+Bubble sort an integer array from lowest to highest.
+This sort does not work on string array.
+
+#### Arguments
+
+- **$1** (array): The input array.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- bubble sorted array.
+
+#### Example
+
+```bash
+iarr=(4 5 1 3)
+array::bsort "${iarr[@]}"
+#Output
+1
+3
+4
+5
+```
+
+### array::merge()
+
+Merge two arrays.
+Pass the variable name of the array instead of value of the variable.
+
+#### Arguments
+
+- **$1** (string): variable name of first array.
+- **$2** (string): variable name of second array.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- Merged array.
+
+#### Example
+
+```bash
+a=("a" "c")
+b=("d" "c")
+array::merge "a[@]" "b[@]"
+#Output
+a
+c
+d
+c
+```
+
+## Check
+
+Helper functions.
+
+### check::command_exists()
+
+Check if the command exists in the system.
+
+#### Arguments
+
+- **$1** (string): Command name to be searched.
+
+#### Exit codes
+
+- **0**: If the command exists.
+- **1**: If the command does not exist.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+check::command_exists "tput"
+```
+
+### check::is_sudo()
+
+Check if the script is executed with sudo privilege.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If the script is executed with root privilege.
+- **1**: If the script is not executed with root privilege
+
+#### Example
+
+```bash
+check::is_sudo
+```
+
+## Collection
+
+(Experimental) Functions to iterates over a list of elements, yielding each in turn to an iteratee function.
+
+### collection::each()
+
+Iterates over elements of collection and invokes iteratee for each element.
+Input to the function can be a pipe output, here-string or file.
+
+#### Arguments
+
+- **$1** (string): Iteratee function.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+- other exitcode returned by iteratee.
+
+#### Output on stdout
+
+- Output of iteratee function.
+
+#### Example
+
+```bash
+test_func(){
+ printf "print value: %s\n" "$1"
+ return 0
+ }
+arr1=("a b" "c d" "a" "d")
+printf "%s\n" "${arr1[@]}" | collection::each "test_func"
+collection::each "test_func" < <(printf "%s\n" "${arr1[@]}") #alternative approach
+#output
+ print value: a b
+ print value: c d
+ print value: a
+ print value: d
+```
+
+#### Example
+
+```bash
+# If other function from this library is already used to process the array.
+# Then following method could be used to pass the array to the function.
+out=("$(array::dedupe "${arr1[@]}")")
+collection::each "test_func" <<< "${out[@]}"
+```
+
+### collection::every()
+
+Checks if iteratee function returns truthy for all elements of collection. Iteration is stopped once predicate returns false.
+Input to the function can be a pipe output, here-string or file.
+
+#### Arguments
+
+- **$1** (string): Iteratee function.
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If iteratee function fails.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+arri=("1" "2" "3" "4")
+printf "%s\n" "${arri[@]}" | collection::every "variable::is_numeric"
+```
+
+### collection::filter()
+
+Iterates over elements of array, returning all elements where iteratee returns true.
+Input to the function can be a pipe output, here-string or file.
+
+#### Arguments
+
+- **$1** (string): Iteratee function.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- array values matching the iteratee function.
+
+#### Example
+
+```bash
+arri=("1" "2" "3" "a")
+printf "%s\n" "${arri[@]}" | collection::filter "variable::is_numeric"
+#output
+1
+2
+3
+```
+
+### collection::find()
+
+Iterates over elements of collection, returning the first element where iteratee returns true.
+Input to the function can be a pipe output, here-string or file.
+
+#### Arguments
+
+- **$1** (string): Iteratee function.
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If no match found.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- first array value matching the iteratee function.
+
+#### Example
+
+```bash
+arr=("1" "2" "3" "a")
+check_a(){
+ [[ "$1" = "a" ]]
+}
+printf "%s\n" "${arr[@]}" | collection::find "check_a"
+#Output
+a
+```
+
+### collection::invoke()
+
+Invokes the iteratee with each element passed as argument to the iteratee.
+Input to the function can be a pipe output, here-string or file.
+
+#### Arguments
+
+- **$1** (string): Iteratee function.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+- other exitcode returned by iteratee.
+
+#### Output on stdout
+
+- Output from the iteratee function.
+
+#### Example
+
+```bash
+opt=("-a" "-l")
+printf "%s\n" "${opt[@]}" | collection::invoke "ls"
+```
+
+### collection::map()
+
+Creates an array of values by running each element in array through iteratee.
+Input to the function can be a pipe output, here-string or file.
+
+#### Arguments
+
+- **$1** (string): Iteratee function.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+- other exitcode returned by iteratee.
+
+#### Output on stdout
+
+- Output result of iteratee on value.
+
+#### Example
+
+```bash
+arri=("1" "2" "3")
+add_one(){
+ i=${1}
+ i=$(( i + 1 ))
+ printf "%s\n" "$i"
+}
+printf "%s\n" "${arri[@]}" | collection::map "add_one"
+```
+
+### collection::reject()
+
+The opposite of filter function; this method returns the elements of collection that iteratee does not return true.
+Input to the function can be a pipe output, here-string or file.
+
+#### Arguments
+
+- **$1** (string): Iteratee function.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- array values not matching the iteratee function.
+
+#### Example
+
+```bash
+arri=("1" "2" "3" "a")
+printf "%s\n" "${arri[@]}" | collection::reject "variable::is_numeric"
+#Ouput
+a
+```
+
+#### See also
+
+- [collection::filter](#collectionfilter)
+
+### collection::some()
+
+Checks if iteratee returns true for any element of the array.
+Input to the function can be a pipe output, here-string or file.
+
+#### Arguments
+
+- **$1** (string): Iteratee function.
+
+#### Exit codes
+
+- **0**: If match successful.
+- **1**: If no match found.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+arr=("a" "b" "3" "a")
+printf "%s\n" "${arr[@]}" | collection::reject "variable::is_numeric"
+```
+
+## Date
+
+Functions for manipulating dates.
+
+### date::now()
+
+Get current time in unix timestamp.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- current timestamp.
+
+#### Example
+
+```bash
+echo "$(date::now)"
+#Output
+1591554426
+```
+
+### date::epoc()
+
+convert datetime string to unix timestamp.
+
+#### Arguments
+
+- **$1** (string): date time in any format.
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp for specified datetime.
+
+#### Example
+
+```bash
+echo "$(date::epoc "2020-07-07 18:38")"
+#Output
+1594143480
+```
+
+### date::add_days_from()
+
+Add number of days from specified timestamp.
+If number of days not specified then it defaults to 1 day.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of days (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_days_from "1594143480")"
+#Output
+1594229880
+```
+
+### date::add_months_from()
+
+Add number of months from specified timestamp.
+If number of months not specified then it defaults to 1 month.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of months (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_months_from "1594143480")"
+#Output
+1596821880
+```
+
+### date::add_years_from()
+
+Add number of years from specified timestamp.
+If number of years not specified then it defaults to 1 year.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of years (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_years_from "1594143480")"
+#Output
+1625679480
+```
+
+### date::add_weeks_from()
+
+Add number of weeks from specified timestamp.
+If number of weeks not specified then it defaults to 1 week.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of weeks (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_weeks_from "1594143480")"
+#Output
+1594748280
+```
+
+### date::add_hours_from()
+
+Add number of hours from specified timestamp.
+If number of hours not specified then it defaults to 1 hour.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of hours (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_hours_from "1594143480")"
+#Output
+1594147080
+```
+
+### date::add_minutes_from()
+
+Add number of minutes from specified timestamp.
+If number of minutes not specified then it defaults to 1 minute.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of minutes (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_minutes_from "1594143480")"
+#Output
+1594143540
+```
+
+### date::add_seconds_from()
+
+Add number of seconds from specified timestamp.
+If number of seconds not specified then it defaults to 1 second.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of seconds (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_seconds_from "1594143480")"
+#Output
+1594143481
+```
+
+### date::add_days()
+
+Add number of days from current day timestamp.
+If number of days not specified then it defaults to 1 day.
+
+#### Arguments
+
+- **$1** (int): number of days (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_days "1")"
+#Output
+1591640826
+```
+
+### date::add_months()
+
+Add number of months from current day timestamp.
+If number of months not specified then it defaults to 1 month.
+
+#### Arguments
+
+- **$1** (int): number of months (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_months "1")"
+#Output
+1594146426
+```
+
+### date::add_years()
+
+Add number of years from current day timestamp.
+If number of years not specified then it defaults to 1 year.
+
+#### Arguments
+
+- **$1** (int): number of years (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_years "1")"
+#Output
+1623090426
+```
+
+### date::add_weeks()
+
+Add number of weeks from current day timestamp.
+If number of weeks not specified then it defaults to 1 year.
+
+#### Arguments
+
+- **$1** (int): number of weeks (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_weeks "1")"
+#Output
+1592159226
+```
+
+### date::add_hours()
+
+Add number of hours from current day timestamp.
+If number of hours not specified then it defaults to 1 hour.
+
+#### Arguments
+
+- **$1** (int): number of hours (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_hours "1")"
+#Output
+1591558026
+```
+
+### date::add_minutes()
+
+Add number of minutes from current day timestamp.
+If number of minutes not specified then it defaults to 1 minute.
+
+#### Arguments
+
+- **$2** (int): number of minutes (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_minutes "1")"
+#Output
+1591554486
+```
+
+### date::add_seconds()
+
+Add number of seconds from current day timestamp.
+If number of seconds not specified then it defaults to 1 second.
+
+#### Arguments
+
+- **$2** (int): number of seconds (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::add_seconds "1")"
+#Output
+1591554427
+```
+
+### date::sub_days_from()
+
+Subtract number of days from specified timestamp.
+If number of days not specified then it defaults to 1 day.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of days (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_days_from "1594143480")"
+#Output
+1594057080
+```
+
+### date::sub_months_from()
+
+Subtract number of months from specified timestamp.
+If number of months not specified then it defaults to 1 month.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of months (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_months_from "1594143480")"
+#Output
+1591551480
+```
+
+### date::sub_years_from()
+
+Subtract number of years from specified timestamp.
+If number of years not specified then it defaults to 1 year.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of years (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_years_from "1594143480")"
+#Output
+1562521080
+```
+
+### date::sub_weeks_from()
+
+Subtract number of weeks from specified timestamp.
+If number of weeks not specified then it defaults to 1 week.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of weeks (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_weeks_from "1594143480")"
+#Output
+1593538680
+```
+
+### date::sub_hours_from()
+
+Subtract number of hours from specified timestamp.
+If number of hours not specified then it defaults to 1 hour.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of hours (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_hours_from "1594143480")"
+#Output
+1594139880
+```
+
+### date::sub_minutes_from()
+
+Subtract number of minutes from specified timestamp.
+If number of minutes not specified then it defaults to 1 minute.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of minutes (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_minutes_from "1594143480")"
+#Output
+1594143420
+```
+
+### date::sub_seconds_from()
+
+Subtract number of seconds from specified timestamp.
+If number of seconds not specified then it defaults to 1 second.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (int): number of seconds (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_seconds_from "1594143480")"
+#Output
+1594143479
+```
+
+### date::sub_days()
+
+Subtract number of days from current day timestamp.
+If number of days not specified then it defaults to 1 day.
+
+#### Arguments
+
+- **$1** (int): number of days (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_days "1")"
+#Output
+1588876026
+```
+
+### date::sub_months()
+
+Subtract number of months from current day timestamp.
+If number of months not specified then it defaults to 1 month.
+
+#### Arguments
+
+- **$1** (int): number of months (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_months "1")"
+#Output
+1559932026
+```
+
+### date::sub_years()
+
+Subtract number of years from current day timestamp.
+If number of years not specified then it defaults to 1 year.
+
+#### Arguments
+
+- **$1** (int): number of years (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_years "1")"
+#Output
+1591468026
+```
+
+### date::sub_weeks()
+
+Subtract number of weeks from current day timestamp.
+If number of weeks not specified then it defaults to 1 week.
+
+#### Arguments
+
+- **$1** (int): number of weeks (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_weeks "1")"
+#Output
+1590949626
+```
+
+### date::sub_hours()
+
+Subtract number of hours from current day timestamp.
+If number of hours not specified then it defaults to 1 hour.
+
+#### Arguments
+
+- **$1** (int): number of hours (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_hours "1")"
+#Output
+1591550826
+```
+
+### date::sub_minutes()
+
+Subtract number of minutes from current day timestamp.
+If number of minutes not specified then it defaults to 1 minute.
+
+#### Arguments
+
+- **$1** (int): number of minutes (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_minutes "1")"
+#Output
+1591554366
+```
+
+### date::sub_seconds()
+
+Subtract number of seconds from current day timestamp.
+If number of seconds not specified then it defaults to 1 second.
+
+#### Arguments
+
+- **$1** (int): number of seconds (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate timestamp.
+
+#### Output on stdout
+
+- timestamp.
+
+#### Example
+
+```bash
+echo "$(date::sub_seconds "1")"
+#Output
+1591554425
+```
+
+### date::format()
+
+Format unix timestamp to human readable format.
+If format string is not specified then it defaults to "yyyy-mm-dd hh:mm:ss" format.
+
+#### Arguments
+
+- **$1** (int): unix timestamp.
+- **$2** (string): format control characters based on `date` command (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If unable to generate time string.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- formatted time string.
+
+#### Example
+
+```bash
+echo echo "$(date::format "1594143480")"
+#Output
+2020-07-07 18:38:00
+```
+
+## Debug
+
+Functions to facilitate debugging scripts.
+
+### debug::print_array()
+
+Prints the content of array as key value pair for easier debugging.
+Pass the variable name of the array instead of value of the variable.
+
+#### Arguments
+
+- **$1** (string): variable name of the array.
+
+#### Output on stdout
+
+- Formatted key value of array.
+
+#### Example
+
+```bash
+array=(foo bar baz)
+printf "Array\n"
+printarr "array"
+declare -A assoc_array
+assoc_array=([foo]=bar [baz]=foobar)
+printf "Assoc Array\n"
+printarr "assoc_array"
+#Output
+Array
+0 = foo
+1 = bar
+2 = baz
+Assoc Array
+baz = foobar
+foo = bar
+```
+
+### debug::print_ansi()
+
+Function to print ansi escape sequence as is.
+This function helps debug ansi escape sequence in text by displaying the escape codes.
+
+#### Arguments
+
+- **$1** (string): input with ansi escape sequence.
+
+#### Output on stdout
+
+- Ansi escape sequence printed in output as is.
+
+#### Example
+
+```bash
+txt="$(tput bold)$(tput setaf 9)This is bold red text$(tput sgr0).$(tput setaf 10)This is green text$(tput sgr0)"
+debug::print_ansi "$txt"
+#Output
+\e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text\e(B\e[m
+```
+
+## File
+
+Functions for handling files.
+
+### file::make_temp_file()
+
+Create temporary file.
+Function creates temporary file with random name. The temporary file will be deleted when script finishes.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If failed to create temp file.
+
+#### Output on stdout
+
+- file name of temporary file created.
+
+#### Example
+
+```bash
+echo "$(file::make_temp_file)"
+#Output
+tmp.vgftzy
+```
+
+### file::make_temp_dir()
+
+Create temporary directory.
+Function creates temporary directory with random name. The temporary directory will be deleted when script finishes.
+
+#### Arguments
+
+- **$1** (string): Temporary directory prefix
+- $2 string Flag to auto remove directory on exit trap (true)
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If failed to create temp directory.
+- **2**: Missing arguments.
+
+#### Output on stdout
+
+- directory name of temporary directory created.
+
+#### Example
+
+```bash
+echo "$(utility::make_temp_dir)"
+#Output
+tmp.rtfsxy
+```
+
+### file::name()
+
+Get only the filename from string path.
+
+#### Arguments
+
+- **$1** (string): path.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- name of the file with extension.
+
+#### Example
+
+```bash
+echo "$(file::name "/path/to/test.md")"
+#Output
+test.md
+```
+
+### file::basename()
+
+Get the basename of file from file name.
+
+#### Arguments
+
+- **$1** (string): path.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- basename of the file.
+
+#### Example
+
+```bash
+echo "$(file::basename "/path/to/test.md")"
+#Output
+test
+```
+
+### file::extension()
+
+Get the extension of file from file name.
+
+#### Arguments
+
+- **$1** (string): path.
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If no extension is found in the filename.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- extension of the file.
+
+#### Example
+
+```bash
+echo "$(file::extension "/path/to/test.md")"
+#Output
+md
+```
+
+### file::dirname()
+
+Get directory name from file path.
+
+#### Arguments
+
+- **$1** (string): path.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- directory path.
+
+#### Example
+
+```bash
+echo "$(file::dirname "/path/to/test.md")"
+#Output
+/path/to
+```
+
+### file::full_path()
+
+Get absolute path of file or directory.
+
+#### Arguments
+
+- **$1** (string): relative or absolute path to file/direcotry.
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If file/directory does not exist.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- Absolute path to file/directory.
+
+#### Example
+
+```bash
+file::full_path "../path/to/file.md"
+#Output
+/home/labbots/docs/path/to/file.md
+```
+
+### file::mime_type()
+
+Get mime type of provided input.
+
+#### Arguments
+
+- **$1** (string): relative or absolute path to file/directory.
+
+#### Exit codes
+
+- **0**: If successful.
+- **1**: If file/directory does not exist.
+- **2**: Function missing arguments.
+- **3**: If file or mimetype command not found in system.
+
+#### Output on stdout
+
+- mime type of file/directory.
+
+#### Example
+
+```bash
+file::mime_type "../src/file.sh"
+#Output
+application/x-shellscript
+```
+
+### file::contains_text()
+
+Search if a given pattern is found in file.
+
+#### Arguments
+
+- **$1** (string): relative or absolute path to file/directory.
+- **$2** (string): search key or regular expression.
+
+#### Exit codes
+
+- **0**: If given search parameter is found in file.
+- **1**: If search paramter not found in file.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+file::contains_text "./file.sh" "^[ @[:alpha:]]*"
+file::contains_text "./file.sh" "@file"
+#Output
+0
+```
+
+## Format
+
+Functions to format provided input.
+
+### format::human_readable_seconds()
+
+Format seconds to human readable format.
+
+#### Arguments
+
+- **$1** (int): number of seconds.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- formatted time string.
+
+#### Example
+
+```bash
+echo "$(format::human_readable_seconds "356786")"
+#Output
+4 days 3 hours 6 minute(s) and 26 seconds
+```
+
+### format::bytes_to_human()
+
+Format bytes to human readable format.
+
+#### Arguments
+
+- **$1** (int): size in bytes.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- formatted file size string.
+
+#### Example
+
+```bash
+echo "$(format::bytes_to_human "2250")"
+#Output
+2.19 KB
+```
+
+### format::strip_ansi()
+
+Remove Ansi escape sequences from given text.
+
+#### Arguments
+
+- **$1** (string): Input text to be ansi stripped.
+
+#### Exit codes
+
+- **0**: If successful.
+
+#### Output on stdout
+
+- Ansi stripped text.
+
+#### Example
+
+```bash
+format::strip_ansi "\e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text.\e(B\e[m"
+#Output
+This is bold red text.This is green text.
+```
+
+### format::text_center()
+
+Prints the given text to centre of terminal.
+
+#### Arguments
+
+- **$1** (string): Text to be printed.
+- **$2** (string): Filler symbol to be added to prefix and suffix of the text (optional). Defaults to space as filler.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- formatted text.
+
+#### Example
+
+```bash
+format::text_center "This text is in centre of the terminal." "-"
+```
+
+### format::report()
+
+Format String to print beautiful report.
+
+#### Arguments
+
+- **$1** (string): Text to be printed on the left.
+- **$2** (string): Text to be printed within the square brackets.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- formatted text.
+
+#### Example
+
+```bash
+format::report "Initialising mission state" "Success"
+#Output
+Initialising mission state ....................................................................[ Success ]
+```
+
+### format::trim_text_to_term()
+
+Trim given text to width of the terminal window.
+
+#### Arguments
+
+- **$1** (string): Text of first sentence.
+- **$2** (string): Text of second sentence (optional).
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- trimmed text.
+
+#### Example
+
+```bash
+format::trim_text_to_term "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." "This is part of second sentence."
+#Output
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..This is part of second sentence.
+```
+
+## Interaction
+
+Functions to enable interaction with the user.
+
+### interaction::prompt_yes_no()
+
+Prompt yes or no question to the user.
+
+#### Arguments
+
+- **$1** (string): The question to be prompted to the user.
+- **$2** (string): default answer \[yes/no\] (optional).
+
+#### Exit codes
+
+- **0**: If user responds with yes.
+- **1**: If user responds with no.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+interaction::prompt_yes_no "Are you sure to proceed" "yes"
+#Output
+Are you sure to proceed (y/n)? [y]
+```
+
+### interaction::prompt_response()
+
+Prompt question to the user.
+
+#### Arguments
+
+- **$1** (string): The question to be prompted to the user.
+- **$2** (string): default answer (optional).
+
+#### Exit codes
+
+- **0**: If user responds with answer.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- User entered answer to the question.
+
+#### Example
+
+```bash
+interaction::prompt_response "Choose directory to install" "/home/path"
+#Output
+Choose directory to install? [/home/path]
+```
+
+## Json
+
+Simple json manipulation. These functions does not completely replace `jq` in any way.
+
+### json::get_value()
+
+Extract value from json based on key and position.
+Input to the function can be a pipe output, here-string or file.
+
+#### Arguments
+
+- **$1** (string): id of the field to fetch.
+- **$2** (int): position of value to extract.Defaults to 1.(optional)
+
+#### Exit codes
+
+- **0**: If match successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- string value of extracted key.
+
+#### Example
+
+```bash
+json::get_value "id" "1" < json_file
+json::get_value "id" <<< "${json_var}"
+echo "{\"data\":{\"id\":\"123\",\"value\":\"name string\"}}" | json::get_value "id"
+```
+
+## Miscellaneous
+
+Set of miscellaneous helper functions.
+
+### misc::check_internet_connection()
+
+Check if internet connection is available.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If script can connect to internet.
+- **1**: If script cannot access internet.
+
+#### Example
+
+```bash
+misc::check_internet_connection
+```
+
+### misc::get_pid()
+
+Get list of process ids based on process name.
+
+#### Arguments
+
+- **$1** (Name): of the process to search.
+
+#### Exit codes
+
+- **0**: If match successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- list of process ids.
+
+#### Example
+
+```bash
+misc::get_pid "chrome"
+#Ouput
+25951
+26043
+26528
+26561
+```
+
+### misc::get_uid()
+
+Get user id based on username.
+
+#### Arguments
+
+- **$1** (username): to search.
+
+#### Exit codes
+
+- **0**: If match successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- string uid for the username.
+
+#### Example
+
+```bash
+misc::get_uid "labbots"
+#Ouput
+1000
+```
+
+### misc::generate_uuid()
+
+Generate random uuid.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If match successful.
+
+#### Output on stdout
+
+- random generated uuid.
+
+#### Example
+
+```bash
+misc::generate_uuid
+#Ouput
+65bc64d1-d355-4ffc-a9d9-dc4f3954c34c
+```
+
+## Operating System
+
+Functions to detect Operating system and version.
+
+### os::detect_os()
+
+Identify the OS the function is run on.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If OS is successfully detected.
+- **1**: If unable to detect OS.
+
+#### Output on stdout
+
+- Operating system name (linux, mac or windows).
+
+#### Example
+
+```bash
+os::detect_os
+#Output
+linux
+```
+
+### os::detect_linux_distro()
+
+Identify the distribution flavour of linux.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If Linux distro is successfully detected.
+- **1**: If unable to detect OS distro.
+
+#### Output on stdout
+
+- Linux OS distribution name (ubuntu, debian, suse, etc.,).
+
+#### Example
+
+```bash
+os::detect_linux_distro
+#Output
+ubuntu
+```
+
+### os::detect_linux_version()
+
+Identify the Linux version.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If Linux version is successfully detected.
+- **1**: If unable to detect Linux version.
+
+#### Output on stdout
+
+- Linux OS version number (18.04, 20.04, etc.,).
+
+#### Example
+
+```bash
+os::detect_linux_version
+#Output
+20.04
+```
+
+### os::detect_mac_version()
+
+Identify the MacOS version.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If MacOS version is successfully detected.
+- **1**: If unable to detect MacOS version.
+
+#### Output on stdout
+
+- MacOS version number (10.15.6, etc.,)
+
+#### Example
+
+```bash
+os::detect_linux_version
+#Output
+10.15.7
+```
+
+## String
+
+Functions for string operations and manipulations.
+
+### string::trim()
+
+Strip whitespace from the beginning and end of a string.
+
+#### Arguments
+
+- **$1** (string): The string to be trimmed.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- The trimmed string.
+
+#### Example
+
+```bash
+echo "$(string::trim " Hello World! ")"
+#Output
+Hello World!
+```
+
+### string::split()
+
+Split a string to array by a delimiter.
+
+#### Arguments
+
+- **$1** (string): The input string.
+- **$2** (string): The delimiter string.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- Returns an array of strings created by splitting the string parameter by the delimiter.
+
+#### Example
+
+```bash
+array=( $(string::split "a,b,c" ",") )
+printf "%s" "$(string::split "Hello!World" "!")"
+#Output
+Hello
+World
+```
+
+### string::lstrip()
+
+Strip characters from the beginning of a string.
+
+#### Arguments
+
+- **$1** (string): The input string.
+- **$2** (string): The characters you want to strip.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- Returns the modified string.
+
+#### Example
+
+```bash
+echo "$(string::lstrip "Hello World!" "He")"
+#Output
+llo World!
+```
+
+### string::rstrip()
+
+Strip characters from the end of a string.
+
+#### Arguments
+
+- **$1** (string): The input string.
+- **$2** (string): The characters you want to strip.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- Returns the modified string.
+
+#### Example
+
+```bash
+echo "$(string::rstrip "Hello World!" "d!")"
+#Output
+Hello Worl
+```
+
+### string::to_lower()
+
+Make a string lowercase.
+
+#### Arguments
+
+- **$1** (string): The input string.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- Returns the lowercased string.
+
+#### Example
+
+```bash
+echo "$(string::to_lower "HellO")"
+#Output
+hello
+```
+
+### string::to_upper()
+
+Make a string all uppercase.
+
+#### Arguments
+
+- **$1** (string): The input string.
+
+#### Exit codes
+
+- **0**: If successful.
+- **2**: Function missing arguments.
+
+#### Output on stdout
+
+- Returns the uppercased string.
+
+#### Example
+
+```bash
+echo "$(string::to_upper "HellO")"
+#Output
+HELLO
+```
+
+### string::contains()
+
+Check whether the search string exists within the input string.
+
+#### Arguments
+
+- **$1** (string): The input string.
+- **$2** (string): The search key.
+
+#### Exit codes
+
+- **0**: If match found.
+- **1**: If no match found.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+string::contains "Hello World!" "lo"
+```
+
+### string::starts_with()
+
+Check whether the input string starts with key string.
+
+#### Arguments
+
+- **$1** (string): The input string.
+- **$2** (string): The search key.
+
+#### Exit codes
+
+- **0**: If match found.
+- **1**: If no match found.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+string::starts_with "Hello World!" "He"
+```
+
+### string::ends_with()
+
+Check whether the input string ends with key string.
+
+#### Arguments
+
+- **$1** (string): The input string.
+- **$2** (string): The search key.
+
+#### Exit codes
+
+- **0**: If match found.
+- **1**: If no match found.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+string::ends_with "Hello World!" "d!"
+```
+
+### string::regex()
+
+Check whether the input string matches the given regex.
+
+#### Arguments
+
+- **$1** (string): The input string.
+- **$2** (string): The search key.
+
+#### Exit codes
+
+- **0**: If match found.
+- **1**: If no match found.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+string::regex "HELLO" "^[A-Z]*$"
+```
+
+## Terminal
+
+Set of useful terminal functions.
+
+### terminal::is_term()
+
+Check if script is run in terminal.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If script is run on terminal.
+- **1**: If script is not run on terminal.
+
+### terminal::detect_profile()
+
+Detect profile rc file for zsh and bash of current script running user.
+
+*Function has no arguments.*
+
+#### Exit codes
+
+- **0**: If script is run on terminal.
+- **1**: If script is not run on terminal.
+
+#### Output on stdout
+
+- path to the profile file.
+
+### terminal::clear_line()
+
+Clear the output in terminal on the specified line number.
+This function clears line only on terminal.
+
+#### Arguments
+
+- **$1** (Line): number to clear. Defaults to 1. (optional)
+
+#### Exit codes
+
+- **0**: If script is run on terminal.
+
+#### Output on stdout
+
+- clear line ansi code.
+
+## Validation
+
+Functions to perform validation on given data.
+
+### validation::email()
+
+Validate whether a given input is a valid email address or not.
+
+#### Arguments
+
+- **$1** (string): input email address to validate.
+
+#### Exit codes
+
+- **0**: If provided input is an email address.
+- **1**: If provided input is not an email address.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+test='test@gmail.com'
+validation::email "${test}"
+echo $?
+#Output
+0
+```
+
+### validation::ipv4()
+
+Validate whether a given input is a valid IP V4 address.
+
+#### Arguments
+
+- **$1** (string): input IPv4 address.
+
+#### Exit codes
+
+- **0**: If provided input is a valid IPv4.
+- **1**: If provided input is not a valid IPv4.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+ips='
+ 4.2.2.2
+ a.b.c.d
+ 192.168.1.1
+ 0.0.0.0
+ 255.255.255.255
+ 255.255.255.256
+ 192.168.0.1
+ 192.168.0
+ 1234.123.123.123
+ 0.192.168.1
+ '
+for ip in $ips; do
+ if validation::ipv4 $ip; then stat='good'; else stat='bad'; fi
+ printf "%-20s: %s\n" "$ip" "$stat"
+done
+#Output
+4.2.2.2 : good
+a.b.c.d : bad
+192.168.1.1 : good
+0.0.0.0 : good
+255.255.255.255 : good
+255.255.255.256 : bad
+192.168.0.1 : good
+192.168.0 : bad
+1234.123.123.123 : bad
+0.192.168.1 : good
+```
+
+### validation::ipv6()
+
+Validate whether a given input is a valid IP V6 address.
+
+#### Arguments
+
+- **$1** (string): input IPv6 address.
+
+#### Exit codes
+
+- **0**: If provided input is a valid IPv6.
+- **1**: If provided input is not a valid IPv6.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+ips='
+ 2001:db8:85a3:8d3:1319:8a2e:370:7348
+ fe80::1ff:fe23:4567:890a
+ fe80::1ff:fe23:4567:890a%eth2
+ 2001:0db8:85a3:0000:0000:8a2e:0370:7334:foo:bar
+ fezy::1ff:fe23:4567:890a
+ ::
+ 2001:db8::
+ '
+for ip in $ips; do
+ if validation::ipv6 $ip; then stat='good'; else stat='bad'; fi
+ printf "%-50s= %s\n" "$ip" "$stat"
+done
+#Output
+2001:db8:85a3:8d3:1319:8a2e:370:7348 = good
+fe80::1ff:fe23:4567:890a = good
+fe80::1ff:fe23:4567:890a%eth2 = good
+2001:0db8:85a3:0000:0000:8a2e:0370:7334:foo:bar = bad
+fezy::1ff:fe23:4567:890a = bad
+:: = good
+2001:db8:: = good
+```
+
+### validation::alpha()
+
+Validate if given variable is entirely alphabetic characters.
+
+#### Arguments
+
+- **$1** (string): Value of variable to validate.
+
+#### Exit codes
+
+- **0**: If input is only alpha characters.
+- **1**: If input contains any non alpha characters.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+test='abcABC'
+validation::alpha "${test}"
+echo $?
+#Output
+0
+```
+
+### validation::alpha_num()
+
+Check if given variable contains only alpha-numeric characters.
+
+#### Arguments
+
+- **$1** (string): Value of variable to validate.
+
+#### Exit codes
+
+- **0**: If input is an alpha-numeric.
+- **1**: If input is not an alpha-numeric.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+test='abc123'
+validation::alpha_num "${test}"
+echo $?
+#Output
+0
+```
+
+### validation::alpha_dash()
+
+Validate if given variable contains only alpha-numeric characters, as well as dashes and underscores.
+
+#### Arguments
+
+- **$1** (string): Value of variable to validate.
+
+#### Exit codes
+
+- **0**: If input is valid.
+- **1**: If input the input is not valid.
+- **2**: Function missing arguments.
+
+#### Example
+
+```bash
+test='abc-ABC_cD'
+validation::alpha_dash "${test}"
+echo $?
+#Output
+0
+```
+
+### validation::version_comparison()
+
+Compares version numbers and provides return based on whether the value in equal, less than or greater.
+
+#### Arguments
+
+- **$1** (string): Version number to check (eg: 1.0.1)
+
+#### Exit codes
+
+- **0**: version number is equal.
+- **1**: $1 version number is greater than $2.
+- **2**: $1 version number is less than $2.
+- **3**: Function is missing required arguments.
+- **4**: Provided input argument is in invalid format.
+
+#### Example
+
+```bash
+test='abc-ABC_cD'
+validation::version_comparison "12.0.1" "12.0.1"
+echo $?
+#Output
+0
+```
+
+## Variable
+
+Functions for handling variables.
+
+### variable::is_array()
+
+Check if given variable is array.
+Pass the variable name instead of value of the variable.
+
+#### Arguments
+
+- **$1** (string): name of the variable to check.
+
+#### Exit codes
+
+- **0**: If input is array.
+- **1**: If input is not an array.
+
+#### Example
+
+```bash
+arr=("a" "b" "c")
+variable::is_array "arr"
+#Output
+0
+```
+
+### variable::is_numeric()
+
+Check if given variable is a number.
+
+#### Arguments
+
+- **$1** (mixed): Value of variable to check.
+
+#### Exit codes
+
+- **0**: If input is number.
+- **1**: If input is not a number.
+
+#### Example
+
+```bash
+variable::is_numeric "1234"
+#Output
+0
+```
+
+### variable::is_int()
+
+Check if given variable is an integer.
+
+#### Arguments
+
+- **$1** (mixed): Value of variable to check.
+
+#### Exit codes
+
+- **0**: If input is an integer.
+- **1**: If input is not an integer.
+
+#### Example
+
+```bash
+variable::is_int "+1234"
+#Output
+0
+```
+
+### variable::is_float()
+
+Check if given variable is a float.
+
+#### Arguments
+
+- **$1** (mixed): Value of variable to check.
+
+#### Exit codes
+
+- **0**: If input is a float.
+- **1**: If input is not a float.
+
+#### Example
+
+```bash
+variable::is_float "+1234.0"
+#Output
+0
+```
+
+### variable::is_bool()
+
+Check if given variable is a boolean.
+
+#### Arguments
+
+- **$1** (mixed): Value of variable to check.
+
+#### Exit codes
+
+- **0**: If input is a boolean.
+- **1**: If input is not a boolean.
+
+#### Example
+
+```bash
+variable::is_bool "true"
+#Output
+0
+```
+
+### variable::is_true()
+
+Check if given variable is a true.
+
+#### Arguments
+
+- **$1** (mixed): Value of variable to check.
+
+#### Exit codes
+
+- **0**: If input is true.
+- **1**: If input is not true.
+
+#### Example
+
+```bash
+variable::is_true "true"
+#Output
+0
+```
+
+### variable::is_false()
+
+Check if given variable is false.
+
+#### Arguments
+
+- **$1** (mixed): Value of variable to check.
+
+#### Exit codes
+
+- **0**: If input is false.
+- **1**: If input is not false.
+
+#### Example
+
+```bash
+variable::is_false "false"
+#Output
+0
+```
+
+### variable::is_empty_or_null()
+
+Check if given variable is empty or null.
+
+#### Arguments
+
+- **$1** (mixed): Value of variable to check.
+
+#### Exit codes
+
+- **0**: If input is empty or null.
+- **1**: If input is not empty or null.
+
+#### Example
+
+```bash
+test=''
+variable::is_empty_or_null $test
+#Output
+0
+```
+
+
+
+## Inspired By
+
+- [Bash Bible](https://github.com/dylanaraps/pure-bash-bible) - A collection of pure bash alternatives to external processes.
+
+## License
+
+[MIT](https://github.com/labbots/google-drive-upload/blob/master/LICENSE)
diff --git a/lib/bash-utility-master/bash_utility.sh b/lib/bash-utility-master/bash_utility.sh
new file mode 100755
index 000000000..65411add0
--- /dev/null
+++ b/lib/bash-utility-master/bash_utility.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# shellcheck disable=SC1091
+source src/array.sh
+source src/string.sh
+source src/variable.sh
+source src/file.sh
+source src/misc.sh
+source src/date.sh
+source src/interaction.sh
+source src/check.sh
+source src/format.sh
+source src/collection.sh
+source src/json.sh
+source src/terminal.sh
+source src/validation.sh
+source src/debug.sh
+source src/os.sh
+
+
diff --git a/lib/bash-utility-master/bin/bashdoc.awk b/lib/bash-utility-master/bin/bashdoc.awk
new file mode 100755
index 000000000..13efdaf7b
--- /dev/null
+++ b/lib/bash-utility-master/bin/bashdoc.awk
@@ -0,0 +1,275 @@
+#!/usr/bin/awk -f
+
+# Varibles
+# style = readme or doc
+# toc = true or false
+BEGIN {
+ if (! style) {
+ style = "doc"
+ }
+
+ if (! toc) {
+ toc = 0
+ }
+
+ styles["empty", "from"] = ".*"
+ styles["empty", "to"] = ""
+
+ styles["h1", "from"] = ".*"
+ styles["h1", "to"] = "# &"
+
+ styles["h2", "from"] = ".*"
+ styles["h2", "to"] = "## &"
+
+ styles["h3", "from"] = ".*"
+ styles["h3", "to"] = "### &"
+
+ styles["h4", "from"] = ".*"
+ styles["h4", "to"] = "#### &"
+
+ styles["h5", "from"] = ".*"
+ styles["h5", "to"] = "##### &"
+
+ styles["code", "from"] = ".*"
+ styles["code", "to"] = "```&"
+
+ styles["/code", "to"] = "```"
+
+ styles["argN", "from"] = "^(\\$[0-9]) (\\S+)"
+ styles["argN", "to"] = "**\\1** (\\2):"
+
+ styles["arg@", "from"] = "^\\$@ (\\S+)"
+ styles["arg@", "to"] = "**...** (\\1):"
+
+ styles["li", "from"] = ".*"
+ styles["li", "to"] = "- &"
+
+ styles["i", "from"] = ".*"
+ styles["i", "to"] = "*&*"
+
+ styles["anchor", "from"] = ".*"
+ styles["anchor", "to"] = "[&](#&)"
+
+ styles["exitcode", "from"] = "([>!]?[0-9]{1,3}) (.*)"
+ styles["exitcode", "to"] = "**\\1**: \\2"
+
+ styles["h_rule", "to"] = "---"
+
+ styles["comment", "from"] = ".*"
+ styles["comment", "to"] = ""
+
+
+ output_format["readme", "h1"] = "h2"
+ output_format["readme", "h2"] = "h3"
+ output_format["readme", "h3"] = "h4"
+ output_format["readme", "h4"] = "h5"
+
+ output_format["bashdoc", "h1"] = "h1"
+ output_format["bashdoc", "h2"] = "h2"
+ output_format["bashdoc", "h3"] = "h3"
+ output_format["bashdoc", "h4"] = "h4"
+
+ output_format["webdoc", "h1"] = "empty"
+ output_format["webdoc", "h2"] = "h3"
+ output_format["webdoc", "h3"] = "h4"
+ output_format["webdoc", "h4"] = "h5"
+
+}
+
+function render(type, text) {
+ if((style,type) in output_format){
+ type = output_format[style,type]
+ }
+ return gensub( \
+ styles[type, "from"],
+ styles[type, "to"],
+ "g",
+ text \
+ )
+}
+
+function render_list(item, anchor) {
+ return "- [" item "](#" anchor ")"
+}
+
+function generate_anchor(text) {
+ # https://github.com/jch/html-pipeline/blob/master/lib/html/pipeline/toc_filter.rb#L44-L45
+ text = tolower(text)
+ gsub(/[^[:alnum:]_ -]/, "", text)
+ gsub(/ /, "-", text)
+ return text
+}
+
+function reset() {
+ has_example = 0
+ has_args = 0
+ has_exitcode = 0
+ has_stdout = 0
+
+ content_desc = ""
+ content_example = ""
+ content_args = ""
+ content_exitcode = ""
+ content_seealso = ""
+ content_stdout = ""
+}
+
+/^[[:space:]]*# @internal/ {
+ is_internal = 1
+}
+
+/^[[:space:]]*# @file/ {
+ sub(/^[[:space:]]*# @file /, "")
+
+ filedoc = render("h1", $0) "\n"
+ if(style == "webdoc"){
+ filedoc = filedoc render("comment", "file=" $0) "\n"
+ }
+
+}
+
+/^[[:space:]]*# @brief/ {
+ sub(/^[[:space:]]*# @brief /, "")
+ if(style == "webdoc"){
+ filedoc = filedoc render("comment", "brief=" $0) "\n"
+ }
+ filedoc = filedoc "\n" $0
+}
+
+/^[[:space:]]*# @description/ {
+ in_description = 1
+ in_example = 0
+
+ reset()
+
+ docblock = ""
+}
+
+in_description {
+ if (/^[^[[:space:]]*#]|^[[:space:]]*# @[^d]|^[[:space:]]*[^#]/) {
+ if (!match(content_desc, /\n$/)) {
+ content_desc = content_desc "\n"
+ }
+ in_description = 0
+ } else {
+ sub(/^[[:space:]]*# @description /, "")
+ sub(/^[[:space:]]*# /, "")
+ sub(/^[[:space:]]*#$/, "")
+
+ content_desc = content_desc "\n" $0
+ }
+}
+
+in_example {
+
+ if (! /^[[:space:]]*#[ ]{3}/) {
+
+ in_example = 0
+
+ content_example = content_example "\n" render("/code") "\n"
+ } else {
+ sub(/^[[:space:]]*#[ ]{3}/, "")
+
+ content_example = content_example "\n" $0
+ }
+}
+
+/^[[:space:]]*# @example/ {
+ in_example = 1
+ content_example = content_example "\n" render("h3", "Example")
+ content_example = content_example "\n\n" render("code", "bash")
+}
+
+/^[[:space:]]*# @arg/ {
+ if (!has_args) {
+ has_args = 1
+
+ content_args = content_args "\n" render("h3", "Arguments") "\n\n"
+ }
+
+ sub(/^[[:space:]]*# @arg /, "")
+
+ $0 = render("argN", $0)
+ $0 = render("arg@", $0)
+
+ content_args = content_args render("li", $0) "\n"
+}
+
+/^[[:space:]]*# @noargs/ {
+ content_args = content_args "\n" render("i", "Function has no arguments.") "\n"
+}
+
+/^[[:space:]]*# @exitcode/ {
+ if (!has_exitcode) {
+ has_exitcode = 1
+
+ content_exitcode = content_exitcode "\n" render("h3", "Exit codes") "\n\n"
+ }
+
+ sub(/^[[:space:]]*# @exitcode /, "")
+
+ $0 = render("exitcode", $0)
+
+ content_exitcode = content_exitcode render("li", $0) "\n"
+}
+
+/^[[:space:]]*# @see/ {
+ sub(/[[:space:]]*# @see /, "")
+ anchor = generate_anchor($0)
+ $0 = render_list($0, anchor)
+
+ content_seealso = content_seealso "\n" render("h3", "See also") "\n\n" $0 "\n"
+}
+
+/^[[:space:]]*# @stdout/ {
+ has_stdout = 1
+
+ sub(/^[[:space:]]*# @stdout /, "")
+
+ content_stdout = content_stdout "\n" render("h3", "Output on stdout")
+ content_stdout = content_stdout "\n\n" render("li", $0) "\n"
+}
+
+{
+ docblock = content_desc content_args content_exitcode content_stdout content_example content_seealso
+ if(style == "webdoc"){
+ docblock = docblock "\n" render("h_rule") "\n"
+ }
+}
+
+/^[ \t]*(function([ \t])+)?([a-zA-Z0-9_:-]+)([ \t]*)(\(([ \t]*)\))?[ \t]*\{/ && docblock != "" && !in_example {
+ if (is_internal) {
+ is_internal = 0
+ } else {
+ func_name = gensub(\
+ /^[ \t]*(function([ \t])+)?([a-zA-Z0-9_:-]+)[ \t]*\(.*/, \
+ "\\3()", \
+ "g" \
+ )
+ doc = doc "\n" render("h2", func_name) "\n" docblock
+ if (toc) {
+ url = generate_anchor(func_name)
+
+ content_idx = content_idx "\n" "- [" func_name "](#" url ")"
+ }
+ }
+
+ docblock = ""
+ reset()
+}
+
+END {
+ if (filedoc != "") {
+ print filedoc
+ }
+
+ if (toc) {
+ print ""
+ print render("h2", "Table of Contents")
+ print content_idx
+ print ""
+ print render("h_rule")
+ }
+
+ print doc
+}
diff --git a/lib/bash-utility-master/bin/generate_readme.sh b/lib/bash-utility-master/bin/generate_readme.sh
new file mode 100755
index 000000000..858a4b8be
--- /dev/null
+++ b/lib/bash-utility-master/bin/generate_readme.sh
@@ -0,0 +1,400 @@
+#!/usr/bin/env bash
+
+#https://github.com/bkrem/make-toc.sh/blob/master/make-toc.sh
+#https://gitlab.com/pedrolab/doctoc.sh/-/blob/master/doctoc.sh
+_usage() {
+ printf "
+Script to autogenerate markdown based on bash source code.\n
+The script generates table of contents and bashdoc and update the given markdown file.\n
+Usage:\n %s [options.. ]\n
+Options:\n
+ -f | --file - Relative or absolute path to the README.md file.
+ -s | --sh-dir - path to the bash script source folder to generate shdocs.\n
+ -l | --toc-level - Minimum level of header to print in Table of Contents.\n
+ -d | --toc-depth - Maximum depth of tree to print in Table of Contents.\n
+ -w | --webdoc - Flag to indicate generation of webdoc.\n
+ -p | --dest-dir - Path in which wedoc files must be generated.\n
+ -h | --help - Display usage instructions.\n" "${0##*/}"
+ exit 0
+}
+
+_setup_arguments() {
+
+ unset MINLEVEL MAXLEVEL SCRIPT_FILE SOURCE_MARKDOWN SOURCE_SCRIPT_DIR SCRIPT_DIR WEBDOC WEBDOC_DEST_DIR
+ MINLEVEL=1
+ MAXLEVEL=3
+ SCRIPT_FILE="${0##*/}"
+ declare source="${BASH_SOURCE[0]}"
+ while [ -h "$source" ]; do # resolve $source until the file is no longer a symlink
+ SCRIPT_DIR="$(cd -P "$(dirname "$source")" > /dev/null 2>&1 && pwd)"
+ source="$(readlink "$source")"
+ [[ $source != /* ]] && source="$SCRIPT_DIR/$source" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
+ done
+ SCRIPT_DIR="$(cd -P "$(dirname "$source")" > /dev/null 2>&1 && pwd)"
+ SOURCE_MARKDOWN="${SCRIPT_DIR}/../README.md"
+ SOURCE_SCRIPT_DIR="${SCRIPT_DIR}/../src"
+ WEBDOC_DEST_DIR="${SCRIPT_DIR}/../hugo-docs/content/functions"
+
+ SHORTOPTS="whp:f:m:d:s:-:"
+
+ while getopts "${SHORTOPTS}" OPTION; do
+ case "${OPTION}" in
+ -)
+ _check_longoptions() { { [[ -z "$1" ]] && printf '%s: --%s: option requires an argument\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1; } || :; }
+ case "${OPTARG}" in
+ help)
+ _usage
+ ;;
+ file)
+ _check_longoptions "${!OPTIND}"
+ SOURCE_MARKDOWN="${!OPTIND}" && OPTIND=$((OPTIND + 1))
+ ;;
+ toc-level)
+ _check_longoptions "${!OPTIND}"
+ MINLEVEL="${!OPTIND}" && OPTIND=$((OPTIND + 1))
+ ;;
+ toc-depth)
+ _check_longoptions "${!OPTIND}"
+ MAXLEVEL="${!OPTIND}" && OPTIND=$((OPTIND + 1))
+ ;;
+ sh-dir)
+ _check_longoptions "${!OPTIND}"
+ SOURCE_SCRIPT_DIR="${!OPTIND}" && OPTIND=$((OPTIND + 1))
+ ;;
+ webdoc)
+ WEBDOC=true
+ ;;
+ dest-dir)
+ WEBDOC_DEST_DIR="${OPTARG}"
+ ;;
+ '')
+ _usage
+ ;;
+ *)
+ printf '%s: --%s: Unknown option\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1
+ ;;
+ esac
+ ;;
+ h)
+ _usage
+ ;;
+ f)
+ SOURCE_MARKDOWN="${OPTARG}"
+ ;;
+ m)
+ MINLEVEL="${OPTARG}"
+ ;;
+ d)
+ MAXLEVEL="${OPTARG}"
+ ;;
+ s)
+ SOURCE_SCRIPT_DIR="${OPTARG}"
+ ;;
+ w)
+ WEBDOC=true
+ ;;
+ p)
+ WEBDOC_DEST_DIR="${OPTARG}"
+ ;;
+ :)
+ printf '%s: -%s: option requires an argument\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1
+ ;;
+ ?)
+ printf '%s: -%s: Unknown option\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1
+ ;;
+ esac
+ done
+ shift "$((OPTIND - 1))"
+
+ if [[ -w "${SOURCE_MARKDOWN}" ]]; then
+ declare src_file src_extension
+ src_file="${SOURCE_MARKDOWN##*/}"
+ src_extension="${src_file##*.}"
+ if [[ "${src_extension,,}" != "md" ]]; then
+ printf "Provided file %s is not a markdown.\n" "${src_file}" && exit 1
+ fi
+ else
+ printf "Provided file %s does not exist or no enough permission to access it.\n" "${SOURCE_MARKDOWN}" && exit 1
+ fi
+
+ if [[ ! -d "${SOURCE_SCRIPT_DIR}" ]]; then
+ printf "Provided directory for bash script files %s does not exist.\n" "${SOURCE_SCRIPT_DIR}" && exit 1
+ fi
+
+ declare re='^[0-9]+$'
+ if ! [[ "${MINLEVEL}" =~ $re ]] || ! [[ "${MAXLEVEL}" =~ $re ]]; then
+ echo "error: Not a number" >&2
+ exit 1
+ fi
+ if [[ "${MINLEVEL}" -gt "${MAXLEVEL}" ]]; then
+ printf "Minimum level for TOC cannot be greater than the depth of TOC to be printed.\n" && exit 1
+ fi
+
+ [ -d "${WEBDOC_DEST_DIR}" ] || mkdir -p "${WEBDOC_DEST_DIR}"
+
+}
+
+_setup_tempfile() {
+ declare temp_file
+ type -p mktemp &> /dev/null && { temp_file="$(mktemp -u)" || temp_file="${PWD}/$((RANDOM * 2)).LOG"; }
+ trap 'rm -f "${temp_file}"' EXIT
+ printf "%s" "${temp_file}"
+}
+
+_generate_shdoc() {
+ declare file
+ file="$(realpath "${1}")"
+ if [[ -s "${file}" ]]; then
+ awk -v style="readme" -v toc=0 -f "${SCRIPT_DIR}"/bashdoc.awk < "${file}" >> "$2"
+ #awk -v style="doc" -v toc=1 -f "${SCRIPT_DIR}"/bashdoc.awk < "${file}" >> "../docs/${file##*/}.md"
+ fi
+}
+
+_insert_shdoc_to_file() {
+ declare shdoc_tmp_file source_markdown start_shdoc info_shdoc end_shdoc
+ shdoc_tmp_file="$1"
+ source_markdown="$2"
+
+ start_shdoc=""
+ info_shdoc=""
+ end_shdoc=""
+
+ sed -i "1s/^/${info_shdoc}\n/" "${shdoc_tmp_file}"
+
+ if grep --color=always -Pzl "(?s)${start_shdoc}.*\n.*${end_shdoc}" "${source_markdown}" &> /dev/null; then
+ # src https://stackoverflow.com/questions/2699666/replace-delimited-block-of-text-in-file-with-the-contents-of-another-file
+
+ sed -i -ne "/${start_shdoc}/ {p; r ${shdoc_tmp_file}" -e ":a; n; /${end_shdoc}/ {p; b}; ba}; p" "${source_markdown}"
+ echo -e "Updated bashdoc content to ${source_markdown} successfully\n"
+
+ else
+ {
+ printf "%s\n" "${start_shdoc}"
+ cat "${shdoc_tmp_file}"
+ printf "%s\n" "${end_shdoc}"
+ } >> "${source_markdown}"
+ echo -e "Created bashdoc content to ${source_markdown} successfully\n"
+ fi
+}
+
+_process_sh_files() {
+ declare shdoc_tmp_file source_script_dir source_markdown
+ source_markdown="${1}"
+ source_script_dir="${2}"
+ shdoc_tmp_file=$(_setup_tempfile)
+ find "${source_script_dir}" -name '*.sh' -print0 | sort -z |
+ while IFS= read -r -d '' line; do
+ _generate_shdoc "${line}" "${shdoc_tmp_file}"
+ done
+ _insert_shdoc_to_file "${shdoc_tmp_file}" "${source_markdown}"
+ rm "${shdoc_tmp_file}"
+
+}
+
+_generate_toc() {
+
+ declare line level title anchor output counter temp_output invalid_chars
+
+ invalid_chars="'[]/?!:\`.,()*\";{}+=<>~$|#@&–—"
+ while IFS='' read -r line || [[ -n "${line}" ]]; do
+ level="$(echo "${line}" | sed -E 's/(#+).*/\1/; s/#/ /g; s/^ //')"
+ title="$(echo "${line}" | sed -E 's/^#+ //')"
+ [[ "${title}" = "Table of Contents" ]] && continue
+
+ # tr does not do OK the lowercase for non ascii chars, add sed to pipeline -> src https://stackoverflow.com/questions/13381746/tr-upper-lower-with-cyrillic-text
+ anchor="$(echo "${title}" | tr '[:upper:] ' '[:lower:]-' | sed 's/[[:upper:]]*/\L&/' | tr -d "${invalid_chars}")"
+
+ # check new line introduced is not duplicated, if is duplicated, introduce a number at the end
+ temp_output=$output"$level- [$title](#$anchor)\n"
+ counter=1
+ while true; do
+ nlines="$(echo -e "${temp_output}" | wc -l)"
+ duplines="$(echo -e "${temp_output}" | sort | uniq | wc -l)"
+ if [ "${nlines}" = "${duplines}" ]; then
+ break
+ fi
+ temp_output=$output"$level- [$title](#$anchor-$counter)\n"
+ counter=$((counter + 1))
+ done
+
+ output="$temp_output"
+
+ # grep: filter header candidates to be included in toc
+ # sed: remove the ignored headers (case: minlevel greater than one) to avoid unnecessary spacing later in level variable assignment
+ done <<< "$(grep -E "^#{${MINLEVEL},${MAXLEVEL}} " "${1}" | tr -d '\r' | sed "s/^#\{$((MINLEVEL - 1))\}//g")"
+
+ # when in toc we have two `--` quit one
+ echo "$output"
+
+}
+
+_insert_toc_to_file() {
+
+ declare source_markdown toc_text start_toc info_toc end_toc toc_block utext_ampersand utext_slash
+ source_markdown="${1}"
+ toc_text="${2}"
+ start_toc=""
+ info_toc=""
+ end_toc=""
+
+ toc_block="$start_toc\n$info_toc\n## Table of Contents\n\n$toc_text\n$end_toc"
+ # temporary replace of '/' (confused with separator of substitutions) and '&' (confused with match regex symbol) to run the special sed command
+ utext_ampersand="id8234923000230gzz"
+ utext_slash="id9992384923423gzz"
+ toc_block="${toc_block//\&/${utext_ampersand}}"
+ toc_block="${toc_block//\//${utext_slash}}"
+
+ # search multiline toc block -> https://stackoverflow.com/questions/2686147/how-to-find-patterns-across-multiple-lines-using-grep/2686705
+ # grep color for debugging -> https://superuser.com/questions/914856/grep-display-all-output-but-highlight-search-matches
+ if grep --color=always -Pzl "(?s)${start_toc}.*\n.*${end_toc}" "${source_markdown}" &> /dev/null; then
+ # src https://askubuntu.com/questions/533221/how-do-i-replace-multiple-lines-with-single-word-in-fileinplace-replace
+ sed -i ":a;N;\$!ba;s/$start_toc.*$end_toc/$toc_block/g" "${source_markdown}"
+ echo -e "Updated TOC content in ${source_markdown} succesfully\n"
+
+ else
+ sed -i 1i"$toc_block" "${source_markdown}"
+ echo -e "Created TOC in ${source_markdown} succesfully\n"
+
+ fi
+
+ # undo symbol replacements
+ sed -i "s,${utext_ampersand},\&,g" "${source_markdown}"
+ sed -i "s,${utext_slash},\/,g" "${source_markdown}"
+
+}
+
+_process_toc() {
+ declare toc_temp_file source_markdown level toc_text
+ source_markdown="${1}"
+
+ toc_temp_file=$(_setup_tempfile)
+
+ sed '/```/,/```/d' "${source_markdown}" > "${toc_temp_file}"
+
+ level=$MINLEVEL
+ while [[ $(grep -Ec "^#{$level} " "${toc_temp_file}") -le 1 ]]; do
+ level=$((level + 1))
+ done
+
+ MINLEVEL=${level}
+ toc_text=$(_generate_toc "${toc_temp_file}")
+ rm "${toc_temp_file}"
+
+ _insert_toc_to_file "${source_markdown}" "${toc_text}"
+}
+
+_generate_webdoc() {
+ declare dest_dir filename file_basename dest_file_path shdoc_tmp_file is_new_file
+ declare title description start_shdoc end_shdoc file_modified_date file_modified_date_epoc
+ declare webdoc_lastmod_date webdoc_lastmod_epoc
+ file="$(realpath "${1}")"
+ dest_dir="${2}"
+
+ filename="${file##*/}"
+ file_basename="${filename%.*}"
+ dest_file_path="${dest_dir}/${file_basename}.md"
+ file_modified_date="$(date -r "${file}" +"%FT%T%:z")"
+ file_modified_date_epoc="$(date -r "${file}" +"%s")"
+
+ start_shdoc=""
+ end_shdoc=""
+ if [[ ! -f "${dest_file_path}" ]]; then
+
+ cat << EOF > "${dest_file_path}"
+---
+title :
+description :
+date : ${file_modified_date}
+lastmod : ${file_modified_date}
+---
+${start_shdoc}
+${end_shdoc}
+EOF
+ is_new_file=true
+ else
+ is_new_file=false
+ webdoc_lastmod_date="$(sed -ne 's/-->//; s/^.*lastmod : //p' "${dest_file_path}")"
+ webdoc_lastmod_epoc="$(date -d "${webdoc_lastmod_date}" +"%s")"
+ fi
+
+ if [[ "${is_new_file}" = true || "${file_modified_date_epoc}" -gt "${webdoc_lastmod_epoc}" ]]; then
+
+ shdoc_tmp_file=$(_setup_tempfile)
+ if [[ -s "${file}" ]]; then
+ awk -v style="webdoc" -v toc=1 -f "${SCRIPT_DIR}"/bashdoc.awk < "${file}" >> "${shdoc_tmp_file}"
+ fi
+
+ if grep --color=always -Pzl "(?s)${start_shdoc}.*\n.*${end_shdoc}" "${dest_file_path}" &> /dev/null; then
+ sed -i -ne "/${start_shdoc}/ {p; r ${shdoc_tmp_file}" -e ":a; n; /${end_shdoc}/ {p; b}; ba}; p" "${dest_file_path}"
+ fi
+
+ # Extract title and description from webdoc
+ title="$(sed -ne 's/-->//; s/^.*//; s/^.*/${title}/g" "${dest_file_path}"
+ sed -i -e "s//${description}/g" "${dest_file_path}"
+ else
+ sed -i -e "s/title : .*/title : ${title}/g" "${dest_file_path}"
+ sed -i -e "s/description : .*/description : ${description}/g" "${dest_file_path}"
+
+ fi
+
+ # Update the last modified timestamp in front matter
+ sed -i -e "s/lastmod : .*/lastmod : ${file_modified_date}/g" "${dest_file_path}"
+
+ echo -e "Updated bashdoc content to ${dest_file_path} successfully."
+ rm "${shdoc_tmp_file}"
+
+ fi
+}
+_process_webdoc_files() {
+ declare source_script_dir dest_dir
+
+ source_script_dir="${1}"
+ dest_dir="${2}"
+
+ find "${source_script_dir}" -name '*.sh' -print0 | sort -z |
+ while IFS= read -r -d '' line; do
+ _generate_webdoc "${line}" "${dest_dir}"
+ done
+}
+
+_count_library_functions() {
+ declare source_script_dir
+ source_script_dir="${1}"
+
+ find "${source_script_dir}" -name '*.sh' -print0 | sort -z |
+ {
+ declare -i function_count=0 count=0
+ while IFS= read -r -d '' line; do
+ count=0
+ count=$(grep -c '^[[:alpha:]]*::[[:alnum:]_]*()' "${line}")
+ function_count=$((function_count + count))
+ done
+ printf "Total library functions: %s \n" "${function_count}"
+
+ }
+}
+main() {
+ # export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
+ # set -x
+ trap 'exit "$?"' INT TERM && trap 'exit "$?"' EXIT
+ set -o errexit -o noclobber -o pipefail
+
+ _setup_arguments "${@}"
+ _process_sh_files "${SOURCE_MARKDOWN}" "${SOURCE_SCRIPT_DIR}"
+ _process_toc "${SOURCE_MARKDOWN}"
+
+ if [[ -n ${WEBDOC} ]]; then
+ _process_webdoc_files "${SOURCE_SCRIPT_DIR}" "${WEBDOC_DEST_DIR}"
+ fi
+ _count_library_functions "${SOURCE_SCRIPT_DIR}"
+}
+
+main "${@}"
diff --git a/lib/bash-utility-master/image/bash-utility.png b/lib/bash-utility-master/image/bash-utility.png
new file mode 100644
index 000000000..c1bfb8b55
Binary files /dev/null and b/lib/bash-utility-master/image/bash-utility.png differ
diff --git a/lib/bash-utility-master/image/logo.png b/lib/bash-utility-master/image/logo.png
new file mode 100644
index 000000000..060ae5b59
Binary files /dev/null and b/lib/bash-utility-master/image/logo.png differ
diff --git a/lib/bash-utility/array.sh b/lib/bash-utility-master/src/array.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/array.sh
rename to lib/bash-utility-master/src/array.sh
diff --git a/lib/bash-utility/check.sh b/lib/bash-utility-master/src/check.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/check.sh
rename to lib/bash-utility-master/src/check.sh
diff --git a/lib/bash-utility/collection.sh b/lib/bash-utility-master/src/collection.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/collection.sh
rename to lib/bash-utility-master/src/collection.sh
diff --git a/lib/bash-utility/date.sh b/lib/bash-utility-master/src/date.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/date.sh
rename to lib/bash-utility-master/src/date.sh
diff --git a/lib/bash-utility/debug.sh b/lib/bash-utility-master/src/debug.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/debug.sh
rename to lib/bash-utility-master/src/debug.sh
diff --git a/lib/bash-utility/file.sh b/lib/bash-utility-master/src/file.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/file.sh
rename to lib/bash-utility-master/src/file.sh
diff --git a/lib/bash-utility/format.sh b/lib/bash-utility-master/src/format.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/format.sh
rename to lib/bash-utility-master/src/format.sh
diff --git a/lib/bash-utility/interaction.sh b/lib/bash-utility-master/src/interaction.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/interaction.sh
rename to lib/bash-utility-master/src/interaction.sh
diff --git a/lib/bash-utility/json.sh b/lib/bash-utility-master/src/json.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/json.sh
rename to lib/bash-utility-master/src/json.sh
diff --git a/lib/bash-utility/misc.sh b/lib/bash-utility-master/src/misc.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/misc.sh
rename to lib/bash-utility-master/src/misc.sh
diff --git a/lib/bash-utility/os.sh b/lib/bash-utility-master/src/os.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/os.sh
rename to lib/bash-utility-master/src/os.sh
diff --git a/lib/bash-utility/string.sh b/lib/bash-utility-master/src/string.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/string.sh
rename to lib/bash-utility-master/src/string.sh
diff --git a/lib/bash-utility/terminal.sh b/lib/bash-utility-master/src/terminal.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/terminal.sh
rename to lib/bash-utility-master/src/terminal.sh
diff --git a/lib/bash-utility/validation.sh b/lib/bash-utility-master/src/validation.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/validation.sh
rename to lib/bash-utility-master/src/validation.sh
diff --git a/lib/bash-utility/variable.sh b/lib/bash-utility-master/src/variable.sh
old mode 100644
new mode 100755
similarity index 100%
rename from lib/bash-utility/variable.sh
rename to lib/bash-utility-master/src/variable.sh
diff --git a/lib/config/benchymark.sh b/lib/config/benchymark.sh
deleted file mode 100644
index 1882c8812..000000000
--- a/lib/config/benchymark.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-
-#
-# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
-#
-# This file is licensed under the terms of the GNU General Public
-# License version 2. This program is licensed "as is" without any
-# warranty of any kind, whether express or implied.
-#
-# Benchmark related functions. See
-# https://systemd.io/ https://www.7-zip.org/ for more info.
-
-# @description system boot-up performance statistics.
-#
-# @example
-# benchymark::see_systemd $1 (-h)
-# #Output
-# armbianmonitor help list options.)
-#
-# @exitcode 0 If successful.
-#
-# @stdout tobd.
-benchymark::see_monitor(){
- [[ $1 == "" ]] && clear && armbianmonitor -h ;
- [[ $1 == $1 ]] && armbianmonitor "$1" ;
- exit 0
- }
-#
-# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
-#
-# This file is licensed under the terms of the GNU General Public
-# License version 2. This program is licensed "as is" without any
-# warranty of any kind, whether express or implied.
-#
-# Benchmark related functions. See
-# https://systemd.io/ for more info.
-# https://www.7-zip.org/
-
-# @description system boot-up performance statistics.
-#
-# @example
-# benchymark::see_systemd $1 (blame time)
-# #Output
-# -h (systemd help list, not not all are avalible.)
-# time (quick check of boot time)
-# balme (Lists modual boot load times)
-#
-# @exitcode 0 If successful.
-#
-# @stdout tobd.
-benchymark::see_boot_times(){
-
- [[ $1 == "" ]] && sys_blame=$( systemd-analyze -h ) ;
- [[ $1 == "blame" ]] && sys_blame=$( systemd-analyze blame ) ;
- [[ $1 == "time" ]] && sys_blame=$( systemd-analyze time ) ;
- printf '%s\n' "${sys_blame[@]}"
- exit 0
- }
diff --git a/lib/config/cpu.sh b/lib/config/cpu.sh
deleted file mode 100644
index 6847be043..000000000
--- a/lib/config/cpu.sh
+++ /dev/null
@@ -1,199 +0,0 @@
-
-#
-# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
-#
-# This file is licensed under the terms of the GNU General Public
-# License version 2. This program is licensed "as is" without any
-# warranty of any kind, whether express or implied.
-#
-# CPU related functions. See https://www.kernel.org/doc/Documentation/cpu-freq/user-guide.txt for more info.
-
-# @description Return policy as int based on original armbian-config logic.
-#
-# @example
-# cpu::get_policy
-# echo $?
-# #Output
-# 0
-#
-# @exitcode 0 If successful.
-#
-# @stdout Policy as integer.
-cpu::see_policy(){
- declare -i policy=0
- [[ $(grep -c '^processor' /proc/cpuinfo) -gt 4 ]] && policy=4
- [[ ! -d /sys/devices/system/cpu/cpufreq/policy4 ]] && policy=0
- [[ -d /sys/devices/system/cpu/cpufreq/policy0 && -d /sys/devices/system/cpu/cpufreq/policy2 ]] && policy=2
- printf '%d\n' "$policy"
-}
-
-# @description Return CPU frequencies as string delimited by space.
-#
-# @example
-# cpu::get_freqs 0
-# echo $?
-# #Output
-# 648000 816000 912000 960000 1008000 1056000 1104000 1152000
-#
-# @arg $1 int policy.
-#
-# @exitcode 0 If successful.
-# @exitcode 1 If file not found.
-# @exitcode 2 Function missing arguments.
-#
-# @stdout Space delimited string of CPU frequencies.
-cpu::see_freqs(){
- # Check number of arguments
- [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
- # Build file based on policy value
- local file="/sys/devices/system/cpu/cpufreq/policy$1/scaling_available_frequencies"
- # Check if file exists
- [ ! -f "$file" ] && printf '%s\n' "$file not found" && return 1
- # Return value
- printf '%s\n' "$(cat $file)"
-}
-
-# @description Return CPU minimum frequency as string.
-#
-# @example
-# cpu::get_min_freq 0
-# echo $?
-# #Output
-# 648000
-#
-# @arg $1 int policy.
-#
-# @exitcode 0 If successful.
-# @exitcode 1 If file not found.
-# @exitcode 2 Function missing arguments.
-#
-# @stdout CPU minimum frequency as string.
-cpu::see_min_freq(){
- # Check number of arguments
- [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
- # Build file based on policy value
- local file="/sys/devices/system/cpu/cpufreq/policy$1/scaling_min_freq"
- # Check if file exists
- [ ! -f "$file" ] && printf '%s\n' "$file not found" && return 1
- # Return value
- printf '%s\n' "$(cat $file)"
-}
-
-# @description Return CPU maximum frequency as string.
-#
-# @example
-# cpu::get_max_freq 0
-# echo $?
-# #Output
-# 1152000
-#
-# @arg $1 int policy.
-#
-# @exitcode 0 If successful.
-# @exitcode 2 Function missing arguments.
-#
-# @stdout CPU maximum frequency as string.
-cpu::see_max_freq(){
- # Check number of arguments
- [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
- # Build file based on policy value
- local file="/sys/devices/system/cpu/cpufreq/policy$1/scaling_max_freq"
- # Check if file exists
- [ ! -f "$file" ] && printf '%s\n' "$file not found" && return 1
- # Return value
- printf '%s\n' "$(cat $file)"
-}
-
-# @description Return CPU governor as string.
-#
-# @example
-# cpu::get_governor 0
-# echo $?
-# #Output
-# performance
-#
-# @arg $1 int policy.
-cpu::see_governor(){
- # Check number of arguments
- [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
- # Build file based on policy value
- local file="/sys/devices/system/cpu/cpufreq/policy$1/scaling_governor"
- # Check if file exists
- [ ! -f "$file" ] && printf '%s\n' "$file not found" && return 1
- # Return value
- printf '%s\n' "$(cat $file)"
-}
-
-# @description Return CPU governors as string delimited by space.
-#
-# @example
-# cpu::get_governors 0
-# echo $?
-# #Output
-# performance
-#
-# @arg $1 int policy.
-cpu::see_governors(){
- # Check number of arguments
- [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
- # Build file based on policy value
- local file="/sys/devices/system/cpu/cpufreq/policy$1/scaling_available_governors"
- # Check if file exists
- [ ! -f "$file" ] && printf '%s\n' "$file not found" && return 1
- # Return value
- printf '%s\n' "$(cat $file)"
-}
-
-# @description Set min, max and CPU governor.
-#
-# @example
-# cpu::set_freq 0 648000 1152000 performance
-# echo $?
-# #Output
-# performance
-#
-# @arg $1 int Policy.
-# @arg $2 int Minimum frequency.
-# @arg $3 int Maximum frequency.
-# @arg $4 string Governor.
-#
-# @exitcode 0 If successful.
-# @exitcode 2 Function missing arguments.
-# @exitcode 3 Invalid minimum frequency.
-# @exitcode 4 Invalid maximum frequency.
-# @exitcode 5 Minimum frequency must be <= maximum frequency.
-# @exitcode 6 Invalid governor.
-cpu::set_freq(){
- # Check number of arguments
- [[ $# -lt 4 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
- # Build file based on policy value
- local file="/etc/default/cpufrequtils"
- # Check if file exists
- [ ! -f "$file" ] && printf '%s\n' "$file not found" && return 1
- declare -i policy=$1
- declare -i min_freq=$2
- declare -i max_freq=$3
- local governor=$4
- # Return frequencies as array
- declare -a freqs=( $(string::split "$(cpu::get_freqs $policy)" " ") )
- # Validate minimum frequency
- array::contains "$min_freq" ${freqs[@]}
- [[ $? != 0 ]] && printf "%s: Invalid minimum frequency\n" "${FUNCNAME[0]}" && return 3
- # Validate maximum frequency
- array::contains "$max_freq" ${freqs[@]}
- [[ $? != 0 ]] && printf "%s: Invalid maximum frequency\n" "${FUNCNAME[0]}" && return 4
- # Validate minimum frequency is <= maximum frequency
- [ "$min_freq" -gt "$max_freq" ] && printf "%s: Minimum frequency must be <= maximum frequency\n" "${FUNCNAME[0]}" && return 5
- # Return governors
- declare -a governors=( $(string::split "$(cpu::get_governors $policy)" " ") )
- # Validate maximum governor
- array::contains "$governor" ${governor[@]}
- [[ $? != 0 ]] && printf "%s: Invalid minimum frequency\n" "${FUNCNAME[0]}" && return 6
- # Update file
- sed -i "s/MIN_SPEED=.*/MIN_SPEED=$min_freq/" "$file"
- sed -i "s/MAX_SPEED=.*/MAX_SPEED=$max_freq/" "$file"
- sed -i "s/GOVERNOR=.*/GOVERNOR=$governor/" "$file"
- # Return value
- return 0
-}
-
diff --git a/lib/config/desktops.sh b/lib/config/desktops.sh
deleted file mode 100644
index 9852e796d..000000000
--- a/lib/config/desktops.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
-#
-# This file is licensed under the terms of the GNU General Public
-# License version 2. This program is licensed "as is" without any
-# warranty of any kind, whether express or implied.
-#
-# Desktop setup related functions. See *(todo)* for more info.
-
-# @description Display a list of avalible desktops to install.
-#
-# @example
-# desktops::see_desktops
-# echo $?
-# #Output
-# 0
-#
-# @exitcode 0 If successful.
-#
-# @stdout list of avalible desktops.
-desktops::see_desktops(){
-
- apt-cache search armbian-$(grep VERSION_CODENAME /etc/os-release | cut -d"=" -f2)-desktop- | cut -d" " -f1
-
- }
\ No newline at end of file
diff --git a/lib/config/extradrives.sh b/lib/config/extradrives.sh
deleted file mode 100644
index dad7a0639..000000000
--- a/lib/config/extradrives.sh
+++ /dev/null
@@ -1,80 +0,0 @@
-
-#
-# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
-#
-# This file is licensed under the terms of the GNU General Public
-# License version 2. This program is licensed "as is" without any
-# warranty of any kind, whether express or implied.
-#
-# Externa Drive related functions. See
-# http://linux-mtd.infradead.org/doc/general.html for more info.
-# https://en.wikipedia.org/wiki/MultiMediaCard#eMMC
-
-# @description Set up a simulated MTD spi flash for testing.
-#
-# @example
-# extradrives::set_spi_vflash
-# echo $?
-# #Output
-# /dev/mtd0
-# /dev/mtd0ro
-# /dev/mtdblock0
-#
-# @exitcode 0 If successful.
-extradrives::set_spi_vflash(){
-
- # Load the nandsim and mtdblock modules to create a virtual MTD device
-
- sudo modprobe mtdblock
- #sudo modprobe nandsim
- # Find the newly created MTD device
- if [[ ! -e /dev/mtdblock0 ]]; then
- sudo modprobe nandsim
- irtual_mtd=$(grep -l "NAND simulator" /sys/class/mtd/mtd*/name | sed -r 's/.*mtd([0-9]+).*/mtd\1/')
- else
- echo "$( sudo ls /dev/mtdblock0 )"
- fi
-
- # Create a symlink to the virtual MTD device with the name "spi0.0"
- # This is necessary because the erase_spi_bootloader function looks for an MTD device with this name
- if [[ ! -e /dev/mtdblock0 ]]; then
- ln -s /dev/$virtual_mtd /dev/mtdblock0
- fi
-
- # Create the mount point if it doesn't exist
- mkdir -p /tmp/boot
-
- # Mount the virtual MTD device to the mount point
- mount -t jffs2 /dev/mtdblock0 /tmp/boot
-
- # write a file to remove
- touch /tmp/boot/Mounted_MTD.txt
-
- echo "$( sudo ls /dev/mtd* )"
-
-}
-
-
-# @description Remove tsting simulated MTD spi flash.
-#
-# @example
-# extradrives::rem_spi_vflash
-# echo $?
-# #Output
-# 0
-#
-# @exitcode 0 If successful.
-extradrives::rem_spi_vflash(){
-
- # Unmount the virtual MTD device from the mount point
- umount $(mount | grep /dev/mtdblock0 | awk '{print $3}')
-
- # Remove the symlink to the virtual MTD device
- rm /dev/mtdblock0
-
- # Unload the nandsim and mtdblock modules to remove the virtual MTD device
- sudo modprobe -r mtdblock
- sudo modprobe -r nandsim
-
- echo "0"
-}
diff --git a/lib/config/iolocal.sh b/lib/config/iolocal.sh
deleted file mode 100644
index 0fd1e263f..000000000
--- a/lib/config/iolocal.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-
-# @description Enable or Disable Infrared Remote Control support.
-#
-# @example
-# io::set_ir_toggle enable
-# io::set_ir_toggle disable
-# echo $?
-# #Output
-# 0
-#
-# @exitcode 0 If successful.
-iolocal::set_ir_toggle(){
-
-[[ "$1" == "enable" ]] && sudo apt -y --no-install-recommends install lirc ; exit 0 ;
-[[ "$1" == "disabe" ]] && sudo apt -y remove lirc ; sudo apt -y -qq autoremove ; exit 0 ;
-
-}
-
-# @description See a list of board led options.
-#
-# @example
-# boardled::set_sysled
-# #Output
-# Led blinks to set $1
-#
-# @exitcode 0 If successful.
-#
-# @stdout tbd.
-boardled::see_sysled_opt(){
-
- # the avalible options
- readarray triggers_led < <( cat /sys/class/leds/*/trigger )
- # see pass not argument the avalible options
- [[ -z $1 ]] && printf "%s\n" "${triggers_led[@]} ";
- exit 0
-}
-
-# @description See a list of board led options.
-#
-# @example
-# boardled::set_sysled
-# #Output
-# Led blinks to set $1
-#
-# @exitcode 0 If successful.
-#
-# @stdout tbd.
-boardled::set_sysled(){
-
- # the avalible options
- readarray triggers_led < <( cat /sys/class/leds/*/trigger )
- # see pass not argument the avalible options
- [[ -z $1 ]] && printf "%s\n" "${triggers_led[@]} ";
- # Set the systme Led blink to $1 valus
- [[ " ${triggers_led[@]} " =~ " ${1} " ]] && echo "${1}"| sudo tee /sys/class/leds/bananapi-m2-zero:red:pwr/trigger ;
-
-}
diff --git a/lib/config/ioremote.sh b/lib/config/ioremote.sh
deleted file mode 100644
index dac2c3de3..000000000
--- a/lib/config/ioremote.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-
-# @description Enable or Disable remote IO devices. (eth, urt, ssh, ... ?)
-#
-# @example
-# io::set_toggle enable
-# io::set_toggle disable
-# echo $?
-# #Output
-# 0
-#
-# @exitcode 0 If successful.
-ioremote::set_toggle(){
-
-[[ "$1" == "" ]] && echo "enable\ndisable";
-[[ "$1" == "enable" ]] && echo "ToDo; enable place holder" ;
-[[ "$1" == "disabe" ]] && echo "ToDo; disable place holder" ;
-
-exit 0
-}
\ No newline at end of file
diff --git a/lib/config/iowirless.sh b/lib/config/iowirless.sh
deleted file mode 100644
index 5858229a9..000000000
--- a/lib/config/iowirless.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-
-# @description Enable or Disable wireless IO devices. (wifi, bluetooth, ... lora?)
-#
-# @example
-# io::set_toggle enable
-# io::set_toggle disable
-# echo $?
-# #Output
-# 0
-#
-# @exitcode 0 If successful.
-iowireless::set_toggle(){
-
-[[ "$1" == "" ]] && echo "enable\ndisable";
-[[ "$1" == "enable" ]] && echo "ToDo; enable place holder" ;
-[[ "$1" == "disabe" ]] && echo "ToDo; disable place holder" ;
-
-}
\ No newline at end of file
diff --git a/share/armbian-configng/armbian-configng.svg b/share/armbian-configng/armbian-configng.svg
new file mode 100644
index 000000000..4d19784d6
--- /dev/null
+++ b/share/armbian-configng/armbian-configng.svg
@@ -0,0 +1,5 @@
+
diff --git a/share/armbian-configng/data/armbian-configng.csv b/share/armbian-configng/data/armbian-configng.csv
new file mode 100755
index 000000000..ee79cbe10
--- /dev/null
+++ b/share/armbian-configng/data/armbian-configng.csv
@@ -0,0 +1,4 @@
+Function Name,Group Name,Description,Options,Category,Category Description
+NMTUI,network,Network Manager.,none.,network,Network Wired wireless Bluetooth access point
+Hello,system,Hello System.,none,system,System and Security
+Bencharking,monitor,Armbian Monitor and Bencharking.,,system,System and Security
diff --git a/share/armbian-configng/data/armbian-configng.json b/share/armbian-configng/data/armbian-configng.json
new file mode 100755
index 000000000..e3a2fea3d
--- /dev/null
+++ b/share/armbian-configng/data/armbian-configng.json
@@ -0,0 +1,26 @@
+[
+ {
+ "Function Name": "NMTUI",
+ "Group Name": "network",
+ "Description": "Network Manager.",
+ "Options": "none.",
+ "Category": "network",
+ "Category Description": "Network Wired wireless Bluetooth access point"
+ },
+ {
+ "Function Name": "Hello",
+ "Group Name": "system",
+ "Description": "Hello System.",
+ "Options": "none",
+ "Category": "system",
+ "Category Description": "System and Security"
+ },
+ {
+ "Function Name": "Bencharking",
+ "Group Name": "monitor",
+ "Description": "Armbian Monitor and Bencharking.",
+ "Options": "",
+ "Category": "system",
+ "Category Description": "System and Security"
+ }
+]
diff --git a/share/armbian-configng/index.html b/share/armbian-configng/index.html
new file mode 100755
index 000000000..d5e3ccce4
--- /dev/null
+++ b/share/armbian-configng/index.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+ Armbian index
+
+
+
+
+