#!/bin/bash
do {
	#////////////////////////////////////
	# DietPi Cloudshell
	#
	#////////////////////////////////////
	# Created by Daniel Knight / daniel.knight@dietpi.com / dietpi.com
	#
	#////////////////////////////////////
	#
	# Info:
	# - System Stats for Cloudshell (or monitor/terminal)
	#
	# Usage:
	# dietpi-cloudshell				= Config Menu
	# dietpi-cloudshell 1			= Run
	# dietpi-cloudshell 2			= Run + Skip intro
	#////////////////////////////////////

	#Grab Input (valid interger)
	setvar INPUT = '0'
	if [[ $1 =~ ^-?[0-9]+$ ]] {
		setvar INPUT = "$1"
	}

	#Import DietPi-Globals ---------------------------------------------------------------
	source /DietPi/dietpi/func/dietpi-globals
	G_CHECK_ROOT_USER
	export G_PROGRAM_NAME='DietPi-Cloudshell'
	#Import DietPi-Globals ---------------------------------------------------------------

	#Version
	setvar DIETPI_CLOUDSHELL_VERSION = '9'

	#/tmp/.* files used throughout this script.
	setvar FP_TEMP = ""/tmp/dietpi-cloudshell""

	setvar PROGRAM_NAME = ""DietPi-Cloudshell""

	setvar BLANK_SCREEN_ACTIVE = '0'
	setvar BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED = '0'
	setvar BLANK_SCREEN_TIME_HOUR_START = '0'
	setvar BLANK_SCREEN_TIME_HOUR_END = '0'

	#This will only work if dietpi-cloudshell was started by autostart (login script), as the setterm power options can only be applied when the command originates from the same terminal (no redirects).
	proc RUN_BLANK_SCREEN_AT_SPECIFIC_TIME {

		local current_hour=$(date +%-H)

		#Turn screen off
		if (( ! $BLANK_SCREEN_ACTIVE )) {

			if (( $BLANK_SCREEN_TIME_HOUR_START == $current_hour )) {
				clear
				echo -e "\n\nScreen will be powered down in under 1 minute\n"
				setterm --blank 1 --powersave on &> /dev/tty1 #blank after 1 minute as force requires a poke to bring it back up.
				setvar BLANK_SCREEN_ACTIVE = '1'
			}

		#Turn screen on
		} elif (( $BLANK_SCREEN_TIME_HOUR_END == $current_hour )) {
			setterm --blank poke &> /dev/tty1
			setterm --reset &> /dev/tty1
			setterm --blank 0 --powersave off &> /dev/tty1
			setvar BLANK_SCREEN_ACTIVE = '0'

		}

	}

	#BC does not allow for printing leading zeros.
	proc BC_ADD_LEADING_ZERO {

		#$1 = string input
		local return_value=$1

		#BC - Add leading zero to start of .* string.
		# +0
		if test ${return_value:0:1} = "." {
			setvar return_value = ""0$return_value""

		# -0
		} elif test ${return_value:0:2} = "-." {
			setvar return_value = $(echo -e "$return_value" | sed 's/^-./-0./')
		}

		echo $return_value

	}

	#Converts a byte int to string, in human readable byte format.
	proc BYTE_PRINT_CONVERSION {

		local return_value=0
		local decimal_count=1

		#$1=byte value

		# - KB
		if (( $1 < 1048576 )) {
			#return_value="$(( $1 / 1024 )) KB"
			setvar return_value = ""$(echo "scale=$decimal_count; $1 / 1024" | bc -l ) KB""

		# - MB
		} elif (( $1 < 1073741824 )) {
			#return_value="$(( $1 / 1024 / 1024 )) MB"
			setvar return_value = ""$(echo "scale=$decimal_count; $1 / 1024 / 1024" | bc -l ) MB""

		# - GB
		} else {
			#return_value="$(( $1 / 1024 / 1024 / 1024 )) GB"
			setvar return_value = ""$(echo "scale=$decimal_count; $1 / 1024 / 1024 / 1024" | bc -l ) GB""

		}

		#BC - Add leading zero to start of .* string.
		setvar return_value = $(BC_ADD_LEADING_ZERO "$return_value")

		echo $return_value

	}

	#Converts a byte int to string, in human readable bit format.
    # - for network data transmission rate (LAN, WLAN, ...)
	# - 1MB = 8Mbit | 1Mbit = 0.125MB
    proc BIT_PRINT_CONVERSION {

		local return_value=0
		local decimal_count=1

		#$1=byte value

		# - Kbit
		if (( $1 < 1000000 )) {
				#return_value="$(( $1 * 8 / 1000 )) Kbit"
				setvar return_value = ""$(echo "scale=$decimal_count; $1 * 8 / 1000" | bc -l) Kbit""

		# - MBit
		} elif (( $1 < 1000000000 )) {
				#return_value="$(( $1 * 8 / 1000 / 1000 )) Mbit"
				setvar return_value = ""$(echo "scale=$decimal_count; $1  * 8 / 1000 / 1000" | bc -l) Mbit""

		# - GBit
		} else {
				#return_value="$(( $1 * 8 / 1000 / 1000 / 1000 )) Gbit"
				setvar return_value = ""$(echo "scale=$decimal_count; $1 * 8 / 1000 / 1000 / 1000" | bc -l) Gbit""

		}

		#BC - Add leading zero to start of .* string.
		setvar return_value = $(BC_ADD_LEADING_ZERO "$return_value")

		echo $return_value

    }

	#Apply fonts
	proc Enable_Term_Options {

		# - Set large font 1st (480x320+)
		setfont /usr/share/consolefonts/Uni3-TerminusBold32x16

		# - set small font if insufficent number of lines (320x240)
		if (( $(tput lines) < 10 )) {

			setfont /usr/share/consolefonts/Uni3-TerminusBold24x12.psf

		}

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Colours
	#/////////////////////////////////////////////////////////////////////////////////////
	setvar C_RESET = ""\e[0m""
	setvar C_REVERSE = ""\e[7m""

	#C_BOLD makes normal text "brighter"
	setvar C_BOLD = ""\e[1m""

	#Colour array
	#0 WHITE
	#1 RED
	#2 GREEN
	#3 YELLOW
	#4 BLUE
	#5 PURPLE
	#6 CYAN
	#7 TEST
	setvar aCOLOUR = ''(
		"\e[39m"
		"\e[31m"
		"\e[32m"
		"\e[33m"
		"\e[34m"
		"\e[35m"
		"\e[36m"
		"\e[93m"
	)

	#user colour
	setvar USER_COLOUR_INDEX = '3'

	setvar C_PERCENT_GRAPH = '0'
	proc Percent_To_Graph {

		#$1 = int/float 0-100
		#$C_PERCENT_GRAPH = return text

		#Convert to int
		local input_value=$(echo $1 | cut -d. -f1)

		#Cap input value
		if (( $input_value > 100 )) {
			setvar input_value = '100'
		} elif (( $input_value < 0 )) {
			setvar input_value = '0'
		}

		#Work out a percentage based graph
		#18 step split (18 / 100)
		if (( $input_value >= 95 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[1]}------WARNING-----$C_RESET]""
		} elif (( $input_value >= 90 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[1]}-----------------$C_RESET-]""
		} elif (( $input_value >= 88 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[1]}----------------$C_RESET--]""
		} elif (( $input_value >= 82 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[1]}---------------$C_RESET---]""
		} elif (( $input_value >= 76 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[3]}--------------$C_RESET----]""
		} elif (( $input_value >= 70 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[3]}-------------$C_RESET-----]""
		} elif (( $input_value >= 64 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[3]}------------$C_RESET------]""
		} elif (( $input_value >= 56 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[3]}-----------$C_RESET-------]""
		} elif (( $input_value >= 50 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[3]}----------$C_RESET--------]""
		} elif (( $input_value >= 44 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[3]}---------$C_RESET---------]""
		} elif (( $input_value >= 38 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[2]}--------$C_RESET----------]""
		} elif (( $input_value >= 32 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[2]}-------$C_RESET-----------]""
		} elif (( $input_value >= 26 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[2]}------$C_RESET------------]""
		} elif (( $input_value >= 20 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[2]}-----$C_RESET-------------]""
		} elif (( $input_value >= 15 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[2]}----$C_RESET--------------]""
		} elif (( $input_value >= 10 )) {
			setvar C_PERCENT_GRAPH = "" $input_value% [$C_REVERSE${aCOLOUR[2]}---$C_RESET---------------]""
		} elif (( $input_value >= 5 )) {
			setvar C_PERCENT_GRAPH = "" $input_value%  [$C_REVERSE${aCOLOUR[2]}--$C_RESET----------------]""
		} else {
			setvar C_PERCENT_GRAPH = "" $input_value%  [$C_REVERSE${aCOLOUR[2]}-$C_RESET-----------------]""
		}

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Obtain Stat Data
	#/////////////////////////////////////////////////////////////////////////////////////
	setvar TEMPERATURE_CONVERSION_VALUE = '0'
	proc Obtain_Temperature_Conversion {

		if (( $TEMPERATURE_OUTPUT_TYPE == 0 )) {
			setvar TEMPERATURE_CONVERSION_VALUE = $(awk "BEGIN {printf \"%.0f\",$TEMPERATURE_CONVERSION_VALUE * 1.8 + 32"})
			setvar TEMPERATURE_CONVERSION_VALUE = ""'f""
		} else {
			setvar TEMPERATURE_CONVERSION_VALUE = ""'c""
		}

	}

	setvar DATE_TIME = '0'
	proc Obtain_DATE_TIME {

		setvar DATE_TIME = $(date +"%a %x - %R")

	}

	setvar UPTIME = '0'
	proc Obtain_UPTIME {

		local fSeconds=$(cat /proc/uptime | awk '{print $1}')

		local seconds=${fSeconds%.*}
		local minutes=0
		local hours=0
		local days=0 {
			((minutes++))
			setvar seconds = $(( $seconds - 60 ))
		} {
			((hours++))
			setvar minutes = $(( $minutes - 60 ))
		} {
			((days++))
			setvar hours = $(( $hours - 24 ))
		}

		setvar UPTIME = ""Uptime: $days Day, $hours Hour""

	}

	#CPU
	setvar CPU_GOV = '0'
	setvar CPU_TEMP = '0'
	setvar C_CPUTEMP = '0'
	setvar CPU_FREQ_1 = '0'
	setvar CPU_FREQ_2 = '0'
	setvar CPU_USAGE = '0'
	setvar CPU_TOTALPROCESSES = '0'
	proc Obtain_CPU {

		setvar CPU_TOTALPROCESSES = $(( $(ps --ppid 2 -p 2 --deselect | wc -l) - 2 )) # - ps process and descriptions.
		setvar CPU_GOV = $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
		setvar CPU_TEMP = $(G_OBTAIN_CPU_TEMP)

		if [[ $CPU_TEMP =~ ^-?[0-9]+$ ]] {

			#Obtain colour for temps
			if (( $CPU_TEMP >= 65 )) {

				setvar C_CPUTEMP = ${aCOLOUR[1]}

			} elif (( $CPU_TEMP >= 50 )) {

				setvar C_CPUTEMP = ${aCOLOUR[3]}

			} elif (( $CPU_TEMP >= 35 )) {

				setvar C_CPUTEMP = ${aCOLOUR[2]}

			} else {

				setvar C_CPUTEMP = ${aCOLOUR[4]}

			}

			#Set 'c or 'f output
			setvar TEMPERATURE_CONVERSION_VALUE = "$CPU_TEMP"
			Obtain_Temperature_Conversion
			setvar CPU_TEMP = "$TEMPERATURE_CONVERSION_VALUE"

		}

		setvar CPU_FREQ_1 = $(( $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 ))
		setvar CPU_FREQ_2 = ""N/A""

		#Unique additional freq readout for Odroid XU4 (octo, 2nd quad set)
		if (( $G_HW_MODEL == 11 )) {

			setvar CPU_FREQ_2 = $(( $(cat /sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq) / 1000 ))

		}

		setvar CPU_USAGE = '0'
		setvar FP_TEMP = ""/tmp/.cpu_usage""

		# PS (inaccurate)
		ps -axo %cpu | sed '1d' | sed 's/ //' > "$FP_TEMP"
		while read -r line
		{

			setvar CPU_USAGE = $( echo "scale=1;$CPU_USAGE + $line" | bc -l )

		} < $FP_TEMP

		#ps returns usage of each core, so we devide the total by #n cores
		setvar CPU_USAGE = $(echo "scale=0;$CPU_USAGE / $G_HW_CPU_CORES" | bc -l )

		# TOP (accurate)
		# Fails to output in low screen res (https://github.com/Fourdee/DietPi/issues/203#issuecomment-189711968)
		# CPU_USAGE=$(BC_ADD_LEADING_ZERO "$(echo "scale=1; 100 - $(top -b -n 1 | grep '%Cpu(s):' | awk '{print $8}')" | bc -l)")

		#convert to interger and graph it
		Percent_To_Graph $CPU_USAGE
		setvar CPU_USAGE = "$C_PERCENT_GRAPH"

	}

	#Storage
	# - array
	setvar MAX_STORAGE = '6'
	setvar STORAGE_TOTAL = ''()
	setvar STORAGE_USED = ''()
	setvar STORAGE_FREE = ''()
	setvar STORAGE_PERCENT = ''()
	setvar STORAGE_PATH = ''()
	setvar STORAGE_NAME = ''()

	proc Init_STORAGE {

		for ((i=0; i<$MAX_STORAGE; i++))
		do
			STORAGE_TOTAL[$i]='N/A'
			STORAGE_USED[$i]='N/A'
			STORAGE_FREE[$i]='N/A'
			STORAGE_PERCENT[$i]=' Not installed'
			STORAGE_NAME[$i]=0

			# 0 reserved for flash storage
			if (( $i == 0 )); then

				STORAGE_PATH[$i]='/'
				STORAGE_NAME[$i]='Flash/RootFS Storage:    '

			else

				STORAGE_PATH[$i]="/mnt/usb_$i"
				STORAGE_NAME[$i]="Storage $i:               "

			fi

		done

	}

	proc Destroy_STORAGE {

		unset STORAGE_TOTAL
		unset STORAGE_USED
		unset STORAGE_FREE
		unset STORAGE_PERCENT
		unset STORAGE_PATH
		unset STORAGE_NAME

	}

	# $1 $2 = Range of indexs to update (eg: 0-1)
	proc Obtain_STORAGE {

		local index_start=$1
		local index_end=$2

		setvar FP_TEMP = ""/tmp/.df""
		rm $FP_TEMP

		#df will endless hang when NFS server is down: https://github.com/Fourdee/DietPi/issues/395
		# - So lets run it as another thread so we can kill it if it hangs.
		local df_failed=0
		df -Ph > $FP_TEMP &
		local pid=$(echo $!)

		# - Wait X seconds before terminating the df thread
		local max_seconds=4
		local current_seconds=0
		while (( $(ps aux | awk '{print $2}' | grep -ci -m1 "$pid$") )) # ! -f may exist, but no data at time of scrape, causing 'mount not found'. so lets wait for process to exit.
		{

			if (( $current_seconds >= $max_seconds )) {

				#kill

				G_DIETPI-NOTIFY 1 "DF failed, unable to obtain drive data"
				sleep 2

				kill $pid

				setvar df_failed = '1'

				echo -e "$(date) | df failed to respond" >> /var/log/dietpi-cloudshell.log

				break

			} else {

				sleep 1
				((current_seconds++))

			}

		}

		if (( $df_failed )) {

			for ((i=$index_start; i<=$index_end; i++))
			do

				STORAGE_PERCENT[$i]="${STORAGE_PATH[$i]}"
				STORAGE_FREE[$i]='DF failed'

			done

		} else {

			for ((i=$index_start; i<=$index_end; i++))
			do

				if (( $(cat $FP_TEMP | grep -ci -m1 "${STORAGE_PATH[$i]}$") )); then

					STORAGE_TOTAL[$i]=$(cat $FP_TEMP | grep -m1 "${STORAGE_PATH[$i]}$" | awk '{print $2}'); STORAGE_TOTAL[$i]+='B'
					STORAGE_USED[$i]=$(cat $FP_TEMP | grep -m1 "${STORAGE_PATH[$i]}$" | awk '{print $3}'); STORAGE_USED[$i]+='B'
					STORAGE_FREE[$i]=$(cat $FP_TEMP | grep -m1 "${STORAGE_PATH[$i]}$" | awk '{print $4}'); STORAGE_FREE[$i]+='B'
					STORAGE_PERCENT[$i]=$(cat $FP_TEMP | grep -m1 "${STORAGE_PATH[$i]}$" | awk '{print $5}' | sed 's/%//g')

					Percent_To_Graph ${STORAGE_PERCENT[$i]}
					STORAGE_PERCENT[$i]=$C_PERCENT_GRAPH

					#DEBUG John:
					echo -e "Results success:\n" >> /var/log/dietpi-cloudshell.log
					echo -e " - Index = $i" >> /var/log/dietpi-cloudshell.log
					echo -e " - Path  = ${STORAGE_PATH[$i]}" >> /var/log/dietpi-cloudshell.log
					echo -e " - Total = ${STORAGE_TOTAL[$i]}" >> /var/log/dietpi-cloudshell.log

				else

					STORAGE_PERCENT[$i]="${STORAGE_PATH[$i]}"
					STORAGE_FREE[$i]='Mount not active'

					#DEBUG John:
					echo -e "$(date) | Mount not found:\n" >> /var/log/dietpi-cloudshell.log
					echo -e " - Index = $i" >> /var/log/dietpi-cloudshell.log
					echo -e " - Path  = ${STORAGE_PATH[$i]}\n" >> /var/log/dietpi-cloudshell.log
					cat "$FP_TEMP" >> /var/log/dietpi-cloudshell.log
					echo -e "\n" >> /var/log/dietpi-cloudshell.log

				fi

			done

		}

	}

	#DietPi
	setvar DIETPI_VERSION_CURRENT = '0'
	setvar DIETPI_UPDATE_AVAILABLE = '0'
	setvar DIETPI_WEBSITE = ''dietpi.com''
	setvar DIETPI_TWITTER = ""@dietpi_""
	setvar DIETPI_HW_DESCRIPTION = ""N/A""
	proc Obtain_DIETPIINFO {

		#DietPi version
		setvar DIETPI_VERSION_CURRENT = ""${aCOLOUR[2]}$(sed -n 1p /DietPi/dietpi/.version).$(sed -n 2p /DietPi/dietpi/.version)$C_RESET""

		#Current HW
		setvar DIETPI_HW_DESCRIPTION = $(sed -n 2p /DietPi/dietpi/.hw_model)

		#DietPi-Update available?
		setvar DIETPI_UPDATE_AVAILABLE = ""N/A""
		if test -f /DietPi/dietpi/.update_available {

			#Set current version to red
			setvar DIETPI_VERSION_CURRENT = ""${aCOLOUR[1]}$(sed -n 1p /DietPi/dietpi/.version).$(sed -n 2p /DietPi/dietpi/.version)$C_RESET""

			local update_version=$(cat /DietPi/dietpi/.update_available)
			if test $update_version = '-1' {

				setvar DIETPI_UPDATE_AVAILABLE = ""${aCOLOUR[2]}New Image$C_RESET""

			} else {

				setvar DIETPI_UPDATE_AVAILABLE = ""${aCOLOUR[2]}$update_version$C_RESET""

			}

		}

	}

	#Network Details
	setvar NETWORK_DETAILS_ADAPTER = ''eth0''
	setvar NETWORK_DETAILS_IP_INT = '0'
	setvar NETWORK_DETAILS_MAC_ADDRESS = '0'
	setvar NETWORK_DETAILS_SIGNAL_STRENGTH = '0'
	setvar NETWORK_DETAILS_DUPLEXSPEED = '0'
	setvar NETWORK_DETAILS_HOSTNAME = '0'
	setvar NETWORK_DETAILS_MODE = '0' #1=dhcp, 0=static
	proc Obtain_NETWORK_DETAILS {

		setvar FP_TEMP = ""/tmp/.ifconfig""

		#Hostname
		setvar NETWORK_DETAILS_HOSTNAME = $(hostname)

		#Active network adapater.
		setvar NETWORK_DETAILS_ADAPTER = $(sed -n 3p /DietPi/dietpi/.network)

		#Mode (dhcp/static)
		if (( $(cat /etc/network/interfaces | grep -ci -m1 "iface $NETWORK_DETAILS_ADAPTER inet dhcp") )) {
			setvar NETWORK_DETAILS_MODE = ""Dhcp""
		} else {
			setvar NETWORK_DETAILS_MODE = ""Static""
		}

		#Ifconfig to /tmp
		ifconfig $NETWORK_DETAILS_ADAPTER > $FP_TEMP

		#IP / MAC addresses
		setvar NETWORK_DETAILS_IP_INT = $(cat "$FP_TEMP" | grep -m1 'inet '| cut -d: -f2 | awk '{ print $1}')
		setvar NETWORK_DETAILS_MAC_ADDRESS = $(cat /sys/class/net/$NETWORK_DETAILS_ADAPTER/address)

		#Speed/Strength
		#Wifi
		if (( $(echo $NETWORK_DETAILS_ADAPTER | grep -ci -m1 'wlan') == 1 )) {
			setvar NETWORK_DETAILS_SIGNAL_STRENGTH = ""$(iwconfig $NETWORK_DETAILS_ADAPTER | grep -m1 'Signal level=' | awk '{ print $4 }' | sed 's/level=//g' | cut -f1 -d "/")%""
			setvar NETWORK_DETAILS_DUPLEXSPEED = ""$(iwconfig $NETWORK_DETAILS_ADAPTER | grep -m1 'Bit Rate:' | awk '{ print $2 }' | sed 's/Rate://g')Mbit""
		#Lan
		} else {
			setvar NETWORK_DETAILS_DUPLEXSPEED = ""$(cat /sys/class/net/$NETWORK_DETAILS_ADAPTER/speed) Mbit""
			#NETWORK_DETAILS_DUPLEXSPEED=$(mii-tool | awk '{print $3}')
			setvar NETWORK_DETAILS_SIGNAL_STRENGTH = ""N/A""
		}

	}

	#Network Usage (all values are in bytes)
	setvar NETWORK_USAGE_TOTAL_CURRENT_SENT = '0'
	setvar NETWORK_USAGE_TOTAL_CURRENT_RECIEVED = '0'

	setvar NETWORK_USAGE_NOW_CURRENT_SENT = '0'
	setvar NETWORK_USAGE_NOW_CURRENT_RECIEVED = '0'
	setvar NETWORK_USAGE_NOW_INIT = '0'
	setvar NETWORK_USAGE_SECONDS_SINCE_LAST_UPDATE = '0'

	setvar NETWORK_USAGE_DAY_CURRENT_SENT = '0'
	setvar NETWORK_USAGE_DAY_CURRENT_RECIEVED = '0'
	setvar NETWORK_USAGE_DAY_PREVIOUS_SENT = '0'
	setvar NETWORK_USAGE_DAY_PREVIOUS_RECIEVED = '0'
	setvar NETWORK_USAGE_DAY_OF_MONTH = '-1'

	proc Obtain_NETWORK_USAGE {

		#Check for valid integer scrapes from netstat, before running calculations: http://dietpi.com/phpbb/viewtopic.php?f=11&t=441&p=1927#p1927 | https://github.com/Fourdee/DietPi/issues/355
		local run_update=1

		local mtu_size=$(netstat -N -i | grep "$NETWORK_DETAILS_ADAPTER" | awk '{print $2}')
		if [[ ! $mtu_size =~ ^-?[0-9]+$ ]] {
			setvar run_update = '0'
		}

		local network_usage_current_recieved=$(netstat -N -i | grep "$NETWORK_DETAILS_ADAPTER" | awk '{print $4}')
		if [[ ! $network_usage_current_recieved =~ ^-?[0-9]+$ ]] {
			setvar run_update = '0'
		}

		local network_usage_current_sent=$(netstat -N -i | grep "$NETWORK_DETAILS_ADAPTER" | awk '{print $8}')
		if [[ ! $network_usage_current_sent =~ ^-?[0-9]+$ ]] {
			setvar run_update = '0'
		}


		if (( $run_update == 1 )) {

			#Store previous totals
			local total_previous_sent=$NETWORK_USAGE_TOTAL_CURRENT_SENT
			local total_previous_recieved=$NETWORK_USAGE_TOTAL_CURRENT_RECIEVED

			#Update current totals
			setvar NETWORK_USAGE_TOTAL_CURRENT_RECIEVED = $(( $network_usage_current_recieved * $mtu_size ))
			setvar NETWORK_USAGE_TOTAL_CURRENT_SENT = $(( $network_usage_current_sent * $mtu_size ))

			#Current usage
			# - Work out seconds since last update
			local seconds_since_last_update=$(( $(date +%s) - $NETWORK_USAGE_SECONDS_SINCE_LAST_UPDATE ))

			# - Init - Override current usage to 0, on first run of scene.
			if (( $NETWORK_USAGE_NOW_INIT == 0 )) {
				setvar NETWORK_USAGE_NOW_CURRENT_SENT = '0'
				setvar NETWORK_USAGE_NOW_CURRENT_RECIEVED = '0'

				setvar NETWORK_USAGE_NOW_INIT = '1'

			# - Obtain current usage
			} else {
				setvar NETWORK_USAGE_NOW_CURRENT_SENT = $(( ( $NETWORK_USAGE_TOTAL_CURRENT_SENT - $total_previous_sent ) / $seconds_since_last_update ))
				setvar NETWORK_USAGE_NOW_CURRENT_RECIEVED = $(( ( $NETWORK_USAGE_TOTAL_CURRENT_RECIEVED - $total_previous_recieved ) / $seconds_since_last_update ))
			}

			# - Update timestamp
			setvar NETWORK_USAGE_SECONDS_SINCE_LAST_UPDATE = $(date +%s)

			# - Ifconfig to /tmp
			#ifconfig $NETWORK_DETAILS_ADAPTER > $FP_TEMP
			#/sys/class/net/ values are being reset by system/kernel when they reach X size. Some sort of "cap".
			#NETWORK_USAGE_TOTAL_CURRENT_SENT=$(( $(cat /sys/class/net/$NETWORK_DETAILS_ADAPTER/statistics/tx_bytes) / 1024 / 1024 ))
			#NETWORK_USAGE_TOTAL_CURRENT_RECIEVED=$(( $(cat /sys/class/net/$NETWORK_DETAILS_ADAPTER/statistics/rx_bytes) / 1024 / 1024 ))

			#Usage today
			# - Has the day changed? Also runs on init.
			#	String if statement, to prevent "leading zero integer error" from $(date): https://github.com/Fourdee/DietPi/issues/272
			local dayofmonth=$(date +"%d")
			if test $NETWORK_USAGE_DAY_OF_MONTH != $dayofmonth {
				#Update previous day values to current
				setvar NETWORK_USAGE_DAY_PREVIOUS_SENT = "$NETWORK_USAGE_TOTAL_CURRENT_SENT"
				setvar NETWORK_USAGE_DAY_PREVIOUS_RECIEVED = "$NETWORK_USAGE_TOTAL_CURRENT_RECIEVED"
				setvar NETWORK_USAGE_DAY_OF_MONTH = "$dayofmonth"

			}

			# - Work out todays usage
			setvar NETWORK_USAGE_DAY_CURRENT_SENT = $(( $NETWORK_USAGE_TOTAL_CURRENT_SENT - $NETWORK_USAGE_DAY_PREVIOUS_SENT ))
			setvar NETWORK_USAGE_DAY_CURRENT_RECIEVED = $(( $NETWORK_USAGE_TOTAL_CURRENT_RECIEVED - $NETWORK_USAGE_DAY_PREVIOUS_RECIEVED ))

		}

	}

	#Memory
	setvar MEMORY_TOTAL = '0'
	setvar MEMORY_FREE = '0'
	setvar MEMORY_USED = '0'
	setvar MEMORY_CACHED = '0'
	setvar MEMORY_PERCENT = '0'
	setvar MEMORY_SWAPTOTAL = '0'
	setvar MEMORY_SWAPUSED = '0'
	setvar MEMORY_SWAPFREE = '0'
	setvar MEMORY_SWAPERCENT = '0'
	proc Obtain_MEMORY {

		#Write to temp
		setvar FP_TEMP = ""/tmp/.mem""
		free -m > $FP_TEMP

		#RAM MB
		setvar MEMORY_TOTAL = $(cat $FP_TEMP | grep -m1 'Mem: ' | awk '{print $2}')
		#Grab values and seperate cache from "used and free" results.
		setvar MEMORY_CACHED = $(cat $FP_TEMP | grep -m1 'Mem: ' | awk '{print $7}')
		setvar MEMORY_USED = $(( $(cat $FP_TEMP | grep -m1 'Mem: ' | awk '{print $3}') - $MEMORY_CACHED ))
		setvar MEMORY_FREE = $(( $(cat $FP_TEMP | grep -m1 'Mem: ' | awk '{print $4}') + $MEMORY_CACHED ))
		setvar MEMORY_PERCENT = $(echo | awk "{print $MEMORY_USED / $MEMORY_TOTAL * 100}")

		#convert to interger and graph it
		Percent_To_Graph $MEMORY_PERCENT
		setvar MEMORY_PERCENT = "$C_PERCENT_GRAPH"

		#SWAP MB
		setvar MEMORY_SWAPTOTAL = $(cat $FP_TEMP | grep -m1 'Swap: ' | awk '{print $2}')
		# - Swap available and active
		if (( $MEMORY_SWAPTOTAL > 0 )) {
			setvar MEMORY_SWAPUSED = $(cat $FP_TEMP | grep -m1 'Swap: ' | awk '{print $3}')
			setvar MEMORY_SWAPFREE = $(cat $FP_TEMP | grep -m1 'Swap: ' | awk '{print $4}')
			setvar MEMORY_SWAPERCENT = $( echo | awk "{print $MEMORY_SWAPUSED / $MEMORY_SWAPTOTAL * 100}")

			#convert to interger and graph it
			Percent_To_Graph $MEMORY_SWAPERCENT
			setvar MEMORY_SWAPERCENT = "$C_PERCENT_GRAPH"
		} else {
			setvar MEMORY_SWAPERCENT = "" Disabled""

		}


	}

	#PI-HOLE STATS!
	setvar PIHOLE_QUERY_COUNT = '0'
	setvar PIHOLE_TOTAL_ADS = '0'
	setvar PIHOLE_PERCENT_ADS = '0'
	setvar PIHOLE_TOTAL_DOMAINS = '0'
	setvar PIHOLE_LAST_DOMAIN_BLOCKED = '0'
	proc Obtain_PIHOLE {

		local pihole_log_file="/var/log/pihole.log"

		#Lets pull the total number of blocked domains only once during 1st run, its quite cpu intensive.
		if (( $PIHOLE_TOTAL_DOMAINS == 0 )) {
			if test -f /etc/pihole/gravity.list {
				setvar PIHOLE_TOTAL_DOMAINS = $(wc -l /etc/pihole/gravity.list | awk '{print $1}')
			} else {
				setvar PIHOLE_TOTAL_DOMAINS = ""Not Installed""
			}

		}

		local today=$(date +'%b %e')

		setvar PIHOLE_QUERY_COUNT = $(cat "$pihole_log_file" | grep "$today" | awk '/query/ {print $7}' | wc -l)
		#Prevent / 0 on percentage
		if (( $PIHOLE_QUERY_COUNT <= 0 )) {
			setvar PIHOLE_QUERY_COUNT = '1'
		}

		setvar PIHOLE_TOTAL_ADS = $(cat "$pihole_log_file" | grep "$today" | awk '/\/etc\/pihole\/gravity.list/ {print $7}' | wc -l)
		setvar PIHOLE_PERCENT_ADS = $(echo | awk "{print $PIHOLE_TOTAL_ADS / $PIHOLE_QUERY_COUNT * 100}")

		#convert to interger and graph it
		Percent_To_Graph $PIHOLE_PERCENT_ADS
		setvar PIHOLE_PERCENT_ADS = "$C_PERCENT_GRAPH"

		#Get last blocked domain
		if (( $PIHOLE_TOTAL_ADS == 0 )) {
			setvar PIHOLE_LAST_DOMAIN_BLOCKED = ""None""
		} else {
			setvar PIHOLE_LAST_DOMAIN_BLOCKED = $(tac /var/log/pihole.log | grep -m1 'gravity.list' | awk '{print $6}' | cut -c 1-24 )
		}

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Scene Settings
	#/////////////////////////////////////////////////////////////////////////////////////
	setvar RUN_INTRO = '0'
	if (( $INPUT == 1 )) {
		setvar RUN_INTRO = '1'
	}

	#SCENE INDEXS
	setvar SCENE_CURRENT = '2'
	setvar MAX_SCENES = '9'

	#Refresh rate (every X seconds)
	setvar REFRESH_RATE = '5'

	#0='f | 1='c
	setvar TEMPERATURE_OUTPUT_TYPE = '1'

	#0=bit (Mbit) | 1=byte (MB)
	setvar NETWORK_USAGE_CURRENT_OUTPUT_TYPE = '0'

	#Enabled Scenes
	setvar aEnabledScenes = ''()
	for ((i=0; i<$MAX_SCENES; i++))
	do
		aEnabledScenes[$i]=1
	done

	#/////////////////////////////////////////////////////////////////////////////////////
	# Scene Print / Update
	#/////////////////////////////////////////////////////////////////////////////////////

	proc Run_Intro {

	   #'--------------------------'
		clear

		local aAnimation=(
			'                          '
			'i         -              c'
			'P  i      -            c l'
			't  P  i   -          c l o'
			'e  t  P  i-        c l o u'
			'i  e  t Pi-    c l o u d s'
			'D  i  etPi-  c l o u d s h'
			'  D  ietPi-c l o u d s h e'
			'    DietPi-cl o u d s h e '
			'    DietPi-clou d s h e l '
			'    DietPi-clouds h e l l '
			'    DietPi-cloudshe l l   '
			'    DietPi-cloudshell     '
		)

		local aBar=(
			' '
			'  '
			'    '
			'       '
			'         '
			'            '
			'               '
			'                 '
			'                    '
			'                      '
			'                        '
			'                         '
			'                          '

		)

		for ((i=0; i<${#aAnimation[@]}; i++))
		do

			clear
			echo -e "$C_RESET"
			echo -e ""
			echo -e ""
			echo -e ""
			echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}${aAnimation[$i]}"
			echo -e "$C_RESET          v$DIETPI_CLOUDSHELL_VERSION"
			echo -e ""
			echo -e "       Loading..."
			echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE${aBar[$i]}"

			sleep 0.2
		done

		#delete[] array
		unset aAnimation
		unset aBar

		sleep 0.1

	}

	#Top banner
	setvar BANNER_PRINT = '0'
	setvar BANNER_MODE = '0'
	proc Update_Banner {

		#Banner Modes
		if (( $BANNER_MODE == 0 )) {
			setvar BANNER_PRINT = ""DietPi - Cloudshell v$DIETPI_CLOUDSHELL_VERSION""
		} elif (( $BANNER_MODE == 1 )) {
			Obtain_DATE_TIME
			setvar BANNER_PRINT = "$DATE_TIME"
		} elif (( $BANNER_MODE == 2 )) {
			Obtain_UPTIME
			setvar BANNER_PRINT = "$UPTIME"
		}

		#Set next index
		((BANNER_MODE++))

		#Cap
		if (( $BANNER_MODE >= 3 )) {
			setvar BANNER_MODE = '0'
		}

	}

	#CPU
	proc Update_Scene_0 {

		#Update data
		Obtain_CPU

		#Clear screen
		clear

		#Banner
		echo -e "$C_RESET $BANNER_PRINT"
		#
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE CPU Usage:               "
		echo -e "$C_RESET$CPU_USAGE"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE CPU Stats:               "
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Temp      ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $C_CPUTEMP$CPU_TEMP"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Processes ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $CPU_TOTALPROCESSES"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Governor  ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $CPU_GOV"

		#XU3/4 unique octo quad sets
		if (( $G_HW_MODEL == 11 )) {
			echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Freq 0-3  ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $CPU_FREQ_1 mhz"
			echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Freq 4-7  ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $CPU_FREQ_2 mhz"

		#Generic CPU hardware
		} else {
			echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Freq      ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $CPU_FREQ_1 mhz"
		}

	}

	#$1 $2 = Storage index's to update and display (must be a range of 1 , eg: 0-1 1-2 3-4)
	proc Update_Scene_1 {

		local index_1=$1
		local index_2=$2

		#Update data
		Obtain_STORAGE $index_1 $index_2

		#Clear screen
		clear

		#Banner
		echo -e "$C_RESET $BANNER_PRINT"
		#
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE ${STORAGE_NAME[$index_1]}"
		echo -e "$C_RESET${STORAGE_PERCENT[$index_1]}"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Used: $C_RESET${STORAGE_USED[$index_1]} / ${STORAGE_TOTAL[$index_1]}"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Free: $C_RESET${STORAGE_FREE[$index_1]}"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE ${STORAGE_NAME[$index_2]}"
		echo -e "$C_RESET${STORAGE_PERCENT[$index_2]}"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Used: $C_RESET${STORAGE_USED[$index_2]} / ${STORAGE_TOTAL[$index_2]}"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Free: $C_RESET${STORAGE_FREE[$index_2]}"

	}

	#DietPi
	proc Update_Scene_4 {

		#Update data
		Obtain_DIETPIINFO

		#Clear screen
		clear

		#Banner
		echo -e "$C_RESET $BANNER_PRINT"
		#
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE DietPi:                  "
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Version   ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $DIETPI_VERSION_CURRENT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Updates   ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $DIETPI_UPDATE_AVAILABLE"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Web       ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $DIETPI_WEBSITE"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Twitter   ${aCOLOUR[$USER_COLOUR_INDEX]}:$C_RESET  $DIETPI_TWITTER"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Device:                  "
		echo -e "$C_RESET $DIETPI_HW_DESCRIPTION"

	}

	#NETWORK DETAILS
	proc Update_Scene_5 {

		#Update data
		Obtain_NETWORK_DETAILS

		#Clear screen
		clear

		#Banner
		echo -e "$C_RESET $BANNER_PRINT"
		#
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Network Details:         "
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} IP      : $C_RESET$NETWORK_DETAILS_IP_INT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Mode    : $C_RESET$NETWORK_DETAILS_MODE"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Adapter : $C_RESET$NETWORK_DETAILS_ADAPTER"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Duplex  : $C_RESET$NETWORK_DETAILS_DUPLEXSPEED"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Signal  : $C_RESET$NETWORK_DETAILS_SIGNAL_STRENGTH"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Hostname: $C_RESET$NETWORK_DETAILS_HOSTNAME"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} MAC: $C_RESET$NETWORK_DETAILS_MAC_ADDRESS"

	}

	#NETWORK USAGE
	proc Update_Scene_6 {

		#Update data
		Obtain_NETWORK_USAGE

		# - Convert usage values into human readable format. Run before clearing screen due to additional processing (delay)
		local total_sent_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_TOTAL_CURRENT_SENT )
		local total_recieved_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_TOTAL_CURRENT_RECIEVED )

		local today_sent_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_DAY_CURRENT_SENT )
		local today_recieved_output=$( BYTE_PRINT_CONVERSION $NETWORK_USAGE_DAY_CURRENT_RECIEVED )

		local now_sent_output=0
		local now_recieved_output0
		if (( $NETWORK_USAGE_CURRENT_OUTPUT_TYPE == 0 )) {
			setvar now_sent_output = $( BIT_PRINT_CONVERSION $NETWORK_USAGE_NOW_CURRENT_SENT )
			setvar now_recieved_output = $( BIT_PRINT_CONVERSION $NETWORK_USAGE_NOW_CURRENT_RECIEVED )
		} else {
			setvar now_sent_output = $( BYTE_PRINT_CONVERSION $NETWORK_USAGE_NOW_CURRENT_SENT )
			setvar now_recieved_output = $( BYTE_PRINT_CONVERSION $NETWORK_USAGE_NOW_CURRENT_RECIEVED )
		}


		#Clear screen
		clear


		#Banner
		# - Banner does not fit this scene (>= 9 lines)
		#echo -e "$C_RESET $BANNER_PRINT"

		#
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Network Usage (TOTAL):   "
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Sent     : $C_RESET$total_sent_output"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Recieved : $C_RESET$total_recieved_output"

		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Network Usage (TODAY):   "
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Sent     : $C_RESET$today_sent_output"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Recieved : $C_RESET$today_recieved_output"

		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Network Usage (CURRENT): "
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Sent     : $C_RESET$now_sent_output/s"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Recieved : $C_RESET$now_recieved_output/s"

	}

	#Memory
	proc Update_Scene_7 {

		#Update data
		Obtain_MEMORY

		#Clear screen
		clear

		#Banner
		echo -e "$C_RESET $BANNER_PRINT"
		#
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Memory Usage (RAM):      "
		echo -e "$C_RESET$MEMORY_PERCENT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Used: $C_RESET$MEMORY_USED MB / $MEMORY_TOTAL MB"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Free: $C_RESET$MEMORY_FREE MB"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Memory Usage (SWAP):     "
		echo -e "$C_RESET$MEMORY_SWAPERCENT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Used: $C_RESET$MEMORY_SWAPUSED MB / $MEMORY_SWAPTOTAL MB"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Free: $C_RESET$MEMORY_SWAPFREE MB"

	}

	#Pi-hole
	proc Update_Scene_8 {

		#Update data
		Obtain_PIHOLE

		#Clear screen
		clear

		#Banner
		echo -e "$C_RESET $BANNER_PRINT"
		#
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Pi-hole stats (TODAY):   "
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Ads Blocked: $C_RESET$PIHOLE_TOTAL_ADS"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} DNS Queries: $C_RESET$PIHOLE_QUERY_COUNT"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]} Blocked Domains: $C_RESET$PIHOLE_TOTAL_DOMAINS"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE % of traffic = Ads:      "
		echo -e "$C_RESET$PIHOLE_PERCENT_ADS"
		echo -e "$C_RESET${aCOLOUR[$USER_COLOUR_INDEX]}$C_REVERSE Last domain blocked:     "
		echo -e "$C_RESET $PIHOLE_LAST_DOMAIN_BLOCKED"

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Settings File
	#/////////////////////////////////////////////////////////////////////////////////////
	#Define Location
	setvar FILEPATH_SETTINGS = ""/DietPi/dietpi/.dietpi-cloudshell""

	proc Read_Settings_File {

		if test -f $FILEPATH_SETTINGS {

			source "$FILEPATH_SETTINGS"

		}

	}

	proc Write_Settings_File {

		cat <<< """ > "$FILEPATH_SETTINGS"
REFRESH_RATE=$REFRESH_RATE
USER_COLOUR_INDEX=$USER_COLOUR_INDEX
TEMPERATURE_OUTPUT_TYPE=$TEMPERATURE_OUTPUT_TYPE
OUTPUT_DISPLAY_INDEX=$OUTPUT_DISPLAY_INDEX

NETWORK_USAGE_CURRENT_OUTPUT_TYPE=$NETWORK_USAGE_CURRENT_OUTPUT_TYPE

BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED=$BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED
BLANK_SCREEN_TIME_HOUR_START=$BLANK_SCREEN_TIME_HOUR_START
BLANK_SCREEN_TIME_HOUR_END=$BLANK_SCREEN_TIME_HOUR_END

"""
> "$FILEPATH_SETTINGS"
REFRESH_RATE=$REFRESH_RATE
USER_COLOUR_INDEX=$USER_COLOUR_INDEX
TEMPERATURE_OUTPUT_TYPE=$TEMPERATURE_OUTPUT_TYPE
OUTPUT_DISPLAY_INDEX=$OUTPUT_DISPLAY_INDEX

NETWORK_USAGE_CURRENT_OUTPUT_TYPE=$NETWORK_USAGE_CURRENT_OUTPUT_TYPE

BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED=$BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED
BLANK_SCREEN_TIME_HOUR_START=$BLANK_SCREEN_TIME_HOUR_START
BLANK_SCREEN_TIME_HOUR_END=$BLANK_SCREEN_TIME_HOUR_END

_EOF_

		#Add enabled scenes
		for ((i=0; i<$MAX_SCENES; i++))
		do

			echo -e "aEnabledScenes[$i]=${aEnabledScenes[$i]}" >> $FILEPATH_SETTINGS

		done

		#Add Drive Paths and Names
		for ((i=0; i<$MAX_STORAGE; i++))
		do

			echo -e "STORAGE_PATH[$i]='${STORAGE_PATH[$i]}'" >> $FILEPATH_SETTINGS
			echo -e "STORAGE_NAME[$i]='${STORAGE_NAME[$i]}'" >> $FILEPATH_SETTINGS

		done

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Init
	#/////////////////////////////////////////////////////////////////////////////////////
	proc Init {

		#--------------------------------------------------------------------------------
		#Storage array
		Init_STORAGE

		#--------------------------------------------------------------------------------
		#Load Settings file.
		Read_Settings_File

		#--------------------------------------------------------------------------------
		#VM disable CPU scene
		if (( $G_HW_MODEL == 20 )) {
			setvar aEnabledScenes[0]=0
		}

		#--------------------------------------------------------------------------------
		#Check and disable scenes if software is not installed:
		# 6 Pi-hole
		if test ! -f /etc/pihole/gravity.list {

			setvar aEnabledScenes[8]=0

		}

		#--------------------------------------------------------------------------------
		#Ensure we have at least 1 Scene enabled in the settings file.
		local enabled_scene=0
		for ((i=0; i<$MAX_SCENES; i++))
		do
			if (( ${aEnabledScenes[$i]} )); then
				enabled_scene=1
				break
			fi
		done

		#No Scenes selected! Override user setting and enable at least 1 scene (dietpi)
		if (( $enabled_scene == 0 )) {

			setvar aEnabledScenes[4]=1
			setvar SCENE_CURRENT = '4'

		}
		#--------------------------------------------------------------------------------
		#Update DietPi network shared data: https://github.com/Fourdee/DietPi/issues/359
		/DietPi/dietpi/func/obtain_network_details

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Start/Stop Control for Menu
	#/////////////////////////////////////////////////////////////////////////////////////
	#0=tty1 1=current
	setvar OUTPUT_DISPLAY_INDEX = '0'

	proc Stop {

		#Service if started.
		systemctl stop dietpi-cloudshell

		#Kill all , excluding Menu.
		ps ax | grep '[d]ietpi-cloudshell [1-9]' | awk '{print $1}' > "$FP_TEMP"
		while read -r line
		{
			kill $line &> /dev/null
		} < $FP_TEMP

	}

	proc Start {

		#Are we starting on the current screen? (eg: from tty1)
		local output_current_screen=0
		if test $(tty) = "/dev/tty1" {
			setvar output_current_screen = '1'
		} elif (( $OUTPUT_DISPLAY_INDEX == 1 )) {
			setvar output_current_screen = '1'
		}

		#Inform user to press CTRL+C to exit
		if (( $output_current_screen == 1 )) {
			clear
			echo -e $C_RESET
			read -p "Use CTRL+C to exit. Press any key to launch $PROGRAM_NAME..."
		}

		#Launch in blocking mode
		if (( $output_current_screen == 1 )) {

			/DietPi/dietpi/dietpi-cloudshell 1

		#Launch as service on main screen
		} else {

			systemctl start dietpi-cloudshell

		}

		sleep 0.1

	}

	#/////////////////////////////////////////////////////////////////////////////////////
	# Menu System
	#/////////////////////////////////////////////////////////////////////////////////////
	setvar WHIP_BACKTITLE = '0'
	setvar WHIP_TITLE = '0'
	setvar WHIP_QUESTION = '0'
	setvar CHOICE = '0'
	setvar TARGETMENUID = '0'
	setvar LASTSELECTED_ITEM = """"

	proc Menu_Exit {

		setvar WHIP_TITLE = ""Exit $PROGRAM_NAME""
		setvar WHIP_QUESTION = ""Exit $PROGRAM_NAME configuration tool?""
		whiptail --title $WHIP_TITLE --yesno $WHIP_QUESTION --backtitle $WHIP_TITLE --yes-button "Ok" --no-button "Back" --defaultno 9 55
		setvar CHOICE = ""$?
		if (( $CHOICE == 0 )) {

			#Save changes
			Write_Settings_File

			#exit
			setvar TARGETMENUID = '-1'

		} else {

			#Return to Main Menu
			setvar TARGETMENUID = '0'

		}

	}

	#TARGETMENUID=0
	proc Menu_Main {

		setvar TARGETMENUID = '0'
		setvar WHIP_BACKTITLE = ""- $PROGRAM_NAME v$DIETPI_CLOUDSHELL_VERSION -""
		setvar WHIP_TITLE = ""- $PROGRAM_NAME -""

		local temp_output_text="Fahrenheit"
		if (( $TEMPERATURE_OUTPUT_TYPE == 1 )) {
			setvar temp_output_text = ""Celsius""
		}

		local target_output_text="Main Screen (tty1)"
		if (( $OUTPUT_DISPLAY_INDEX == 1 )) {
			setvar target_output_text = ""Current screen or terminal""
		}

		local bitbyte_output_text="Bit (Kbit, Mbit, Gbit)"
		if (( $NETWORK_USAGE_CURRENT_OUTPUT_TYPE == 1 )) {
			setvar bitbyte_output_text = ""Byte (KB, MB, GB)""
		}

		local autoscreenoff="Disabled"
		if (( $BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED )) {
			setvar autoscreenoff = ""Enabled""
		}

		setvar OPTION = $(whiptail --title "$WHIP_TITLE" --backtitle "$WHIP_BACKTITLE" --menu "" --cancel-button "Exit" --default-item "$LASTSELECTED_ITEM" 17 75 10 \
		"Colour" "Setting: Change the colour scheme." \
		"Update Rate" "Setting: Control the time between screen updates." \
		"Scenes" "Setting: Toggle which scenes are shown." \
		"Storage" "Setting: Set mount locations used for storage stats" \
		"Temperature" "Setting: Output = $temp_output_text" \
		"Net Usage Current" "Setting: Output = $bitbyte_output_text" \
		"Output Display" "Setting: $target_output_text." \
		"Auto screen off" "Setting: $autoscreenoff | Start $BLANK_SCREEN_TIME_HOUR_START h | End $BLANK_SCREEN_TIME_HOUR_END h" \
		"Start / Restart" "Apply settings. Launch on $target_output_text." \
		"Stop" "Stops $PROGRAM_NAME."  3>&1 1>&2 2>&3)

		setvar CHOICE = ""$?
		if (( $CHOICE == 0 )) {

			setvar LASTSELECTED_ITEM = "$OPTION"

			case (OPTION) {

				"Storage" {
					setvar TARGETMENUID = '5'
				}
				"Auto screen off" {
					setvar TARGETMENUID = '4'
				}
				"Net Usage Current" {
					((NETWORK_USAGE_CURRENT_OUTPUT_TYPE++))
					if (( $NETWORK_USAGE_CURRENT_OUTPUT_TYPE > 1 )) {
						setvar NETWORK_USAGE_CURRENT_OUTPUT_TYPE = '0'
					}
				}
				Temperature {
					((TEMPERATURE_OUTPUT_TYPE++))
					if (( $TEMPERATURE_OUTPUT_TYPE > 1 )) {
						setvar TEMPERATURE_OUTPUT_TYPE = '0'
					}
				}
				"Output Display" {
					((OUTPUT_DISPLAY_INDEX++))
					if (( $OUTPUT_DISPLAY_INDEX > 1 )) {
						setvar OUTPUT_DISPLAY_INDEX = '0'
					}
				}
				"Start / Restart" {
					Write_Settings_File
					Stop
					Start
				}
				"Stop" {
					Stop
				}
				Colour {
					setvar TARGETMENUID = '1'
				}
				"Update Rate" {
					setvar TARGETMENUID = '2'
				}
				Scenes {
					setvar TARGETMENUID = '3'
				}
			}
		} else {
			Menu_Exit
		}

	}

	#TARGETMENUID=1
	proc Menu_Colour {

		#Return to main menu
		setvar TARGETMENUID = '0'

		#Colour array
		#0 WHITE
		#1 RED
		#2 GREEN
		#3 YELLOW
		#4 BLUE
		#5 PURPLE
		#6 CYAN
		setvar WHIP_TITLE = ''- Options : Colour -''
		setvar WHIP_QUESTION = ''Select your colour scheme.''
		setvar OPTION = $(whiptail --title "$WHIP_TITLE" --backtitle "$WHIP_BACKTITLE" --menu "$WHIP_QUESTION" --cancel-button "Back" --default-item "$USER_COLOUR_INDEX" 15 45 7 \
		"0" "White" \
		"1" "Red" \
		"2" "Green" \
		"3" "Yellow (Default)" \
		"4" "Blue" \
		"5" "Purple" \
		"6" "Cyan"  3>&1 1>&2 2>&3)

		setvar CHOICE = ""$?
		if (( $CHOICE == 0 )) {

			setvar USER_COLOUR_INDEX = "$OPTION"

		}

	}

	#TARGETMENUID=2
	proc Menu_UpdateRate {

		#Return to main menu
		setvar TARGETMENUID = '0'

		setvar WHIP_TITLE = ''- Options : Update Rate -''
		setvar WHIP_QUESTION = ''Change the delay between scene changes and updates.''
		setvar OPTION = $(whiptail --title "$WHIP_TITLE" --backtitle "$WHIP_BACKTITLE" --menu "$WHIP_QUESTION" --cancel-button "Back" --default-item "$REFRESH_RATE" 15 55 7 \
		"1" "Second" \
		"3" "Seconds" \
		"5" "Seconds (Default)" \
		"10" "Seconds" \
		"15" "Seconds" \
		"20" "Seconds" \
		"30" "Seconds" \
		"45" "Seconds" \
		"60" "Seconds" 3>&1 1>&2 2>&3)

		setvar CHOICE = ""$?
		if (( $CHOICE == 0 )) {

			setvar REFRESH_RATE = "$OPTION"

		}

	}

	#TARGETMENUID=3
	proc Menu_SceneSelection {

		#Return to main menu
		setvar TARGETMENUID = '0'

		setvar FP_TEMP = ""/tmp/.dietpi-cloudshell_scenelist""

		#Get on/off whilptail status
		local aWhiptailArray=()
		local aWhip_OnOff_Status=()
		for ((i=0; i<$MAX_SCENES; i++))
		do
			#On/Off status
			aWhip_OnOff_Status[$i]='on'
			if (( ! ${aEnabledScenes[$i]} )); then

				aWhip_OnOff_Status[$i]='off'

			fi

		done

		#Define options
		local index=0
		setvar index = '0';setvar aWhiptailArray = ''("$index" "CPU: Temperatures, Usage, frequency and more." "${aWhip_OnOff_Status[$index]}")
		setvar index = '1';setvar aWhiptailArray = ''("$index" "Storage: Usage information for Flash and USB drives" "${aWhip_OnOff_Status[$index]}")
		setvar index = '2';setvar aWhiptailArray = ''("$index" " - Additional Storage (USB_2/3)" "${aWhip_OnOff_Status[$index]}")
		setvar index = '3';setvar aWhiptailArray = ''("$index" " - Additional Storage (USB_4/5)" "${aWhip_OnOff_Status[$index]}")
		setvar index = '4';setvar aWhiptailArray = ''("$index" "DietPi: Information, stats and updates for DietPi." "${aWhip_OnOff_Status[$index]}")
		setvar index = '5';setvar aWhiptailArray = ''("$index" "Network Details: Ip address, Speeds, Signal and more." "${aWhip_OnOff_Status[$index]}")
		setvar index = '6';setvar aWhiptailArray = ''("$index" "Network Usage: Bandwidth usage (sent / recieved)." "${aWhip_OnOff_Status[$index]}")
		setvar index = '7';setvar aWhiptailArray = ''("$index" "Memory: Stats for RAM and Swapfile usage." "${aWhip_OnOff_Status[$index]}")
		setvar index = '8';setvar aWhiptailArray = ''("$index" "Pi-hole: Stats for Pi-hole. Total Ads blocked etc." "${aWhip_OnOff_Status[$index]}")

		setvar WHIP_TITLE = ''- Options : Scene Selection -''
		setvar WHIP_QUESTION = ''Please use the spacebar to toggle which scenes are active.''
		whiptail --title $WHIP_TITLE --checklist $WHIP_QUESTION --backtitle $WHIP_TITLE --separate-output 16 75 9 ${aWhiptailArray[@]} 2> "$FP_TEMP"
		setvar CHOICE = ""$?

		#Delete[] array
		unset aWhiptailArray
		unset aWhip_OnOff_Status

		# - Reset all scenes to 0
		if (( $CHOICE == 0 )) {

			for ((i=0; i<$MAX_SCENES; i++))
			do
				aEnabledScenes[$i]=0

			done

		}

		# - Enable required scenes
		while read -r line
		{

			setvar aEnabledScenes[$line]=1

		} < "$FP_TEMP"

	}

	#TARGETMENUID=4
	proc Menu_BlankScreenAtTime {

		#Return to main menu
		setvar TARGETMENUID = '0'

		#generate 24 hour array
		local aWhipHour=()
		for ((i=0; i<24; i++))
		do
			aWhipHour+=("$i" "Hour")

		done

		local blank_screen_at_specific_time_enabled_text='Disabled'
		if (( $BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED )) {
			setvar blank_screen_at_specific_time_enabled_text = ''Enabled''
		}

		setvar WHIP_TITLE = ''- Options : Auto screen off -''
		setvar WHIP_QUESTION = ''Automatically power down the screen and disable DietPi-Cloudshell processing during a specific time.\n\nNB: This feature will only work if DietPi-Cloudshell was launched with the DietPi-Autostart option, or, launched from the main screen (tty1).''
		setvar OPTION = $(whiptail --title "$WHIP_TITLE" --backtitle "$WHIP_BACKTITLE" --menu "$WHIP_QUESTION" --cancel-button "Back" --default-item "$REFRESH_RATE" 16 60 3 \
		"Toggle" "$blank_screen_at_specific_time_enabled_text" \
		"Start time" "Set which hour to power off screen ($BLANK_SCREEN_TIME_HOUR_START)." \
		"End time" "Set which hour to power on screen ($BLANK_SCREEN_TIME_HOUR_END)." 3>&1 1>&2 2>&3)

		setvar CHOICE = ""$?
		if (( $CHOICE == 0 )) {

			if test $OPTION = "Toggle"{

				((BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED++))
				if (( $BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED > 1 )) {
					setvar BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED = '0'
				}

			} elif test $OPTION = "Start time"{

				setvar WHIP_QUESTION = ''Please select which hour (24h) you would like the screen to power off.''
				setvar OPTION = $(whiptail --title "$WHIP_TITLE" --menu "$WHIP_QUESTION" --default-item "$BLANK_SCREEN_TIME_HOUR_START" --backtitle "$WHIP_BACKTITLE" 16 55 7 "${aWhipHour[@]}" 3>&1 1>&2 2>&3)
				setvar CHOICE = ""$?
				if (( $CHOICE == 0 )) {
					setvar BLANK_SCREEN_TIME_HOUR_START = "$OPTION"
				}

			} elif test $OPTION = "End time"{

				setvar WHIP_QUESTION = ''Please select which hour (24h) you would like the screen to power on.''
				setvar OPTION = $(whiptail --title "$WHIP_TITLE" --menu "$WHIP_QUESTION" --default-item "$BLANK_SCREEN_TIME_HOUR_END" --backtitle "$WHIP_BACKTITLE" 16 55 7 "${aWhipHour[@]}" 3>&1 1>&2 2>&3)
				setvar CHOICE = ""$?
				if (( $CHOICE == 0 )) {
					setvar BLANK_SCREEN_TIME_HOUR_END = "$OPTION"
				}

			}

			setvar TARGETMENUID = '4'

		}

		unset aWhipHour

	}

	#TARGETMENUID=5
	proc Menu_Storage {

		#Return to main menu
		setvar TARGETMENUID = '0'

		local aWhiptailArray=()

		for ((i=1; i<$MAX_STORAGE; i++))
		do

			#aWhiptailArray+=("Name $i" "${STORAGE_NAME[$i]}.")
			aWhiptailArray+=("$i" ": Drive $i | ${STORAGE_PATH[$i]}")

		done

		setvar WHIP_TITLE = ''- Options : Storage Device Mount Location -''
		setvar WHIP_QUESTION = ''DietPi-Cloudshell pulls the storage stats from the drive mount location. If you have custom drives/mounts, please set them here to be displayed during storage scene updates.\n\n - Drive 1 = Displayed during main storage scene\n - Drive 2/3 = Displayed during additional storage scene\n - Drive 4/5 = Displayed during additional storage scene''
		setvar OPTION = $(whiptail --title "$WHIP_TITLE" --backtitle "$PROGRAM_NAME" --menu "$WHIP_QUESTION" --cancel-button "Back" 19 75 5 "${aWhiptailArray[@]}" 3>&1 1>&2 2>&3)

		setvar CHOICE = ""$?

		unset aWhiptailArray

		if (( $CHOICE == 0 )) {

			local index=$OPTION

			/DietPi/dietpi/dietpi-drive_manager 1
			local return_string="$(cat /tmp/dietpi-drive_manager_selmnt)"
			if test -n $return_string {

				setvar STORAGE_PATH[$index]="$return_string"

			}

			setvar TARGETMENUID = '5'

		}

	}


	#/////////////////////////////////////////////////////////////////////////////////////
	# MAIN
	#/////////////////////////////////////////////////////////////////////////////////////
	#-----------------------------------------------------------------------------------
	#Init
	Init
	#-----------------------------------------------------------------------------------
	#Run menu
	if (( $INPUT == 0 )) { {

			clear

			if (( $TARGETMENUID == 0 )) {
				Menu_Main
			} elif (( $TARGETMENUID == 1 )) {
				Menu_Colour
			} elif (( $TARGETMENUID == 2 )) {
				Menu_UpdateRate
			} elif (( $TARGETMENUID == 3 )) {
				Menu_SceneSelection
			} elif (( $TARGETMENUID == 4 )) {
				Menu_BlankScreenAtTime
			} elif (( $TARGETMENUID == 5 )) {
				Menu_Storage
			}

		}

	#-----------------------------------------------------------------------------------
	#Run DietPi-Cloudshell
	} elif (( $INPUT >= 1 )) {

		Enable_Term_Options

		#Start Intro
		if (( $RUN_INTRO )) {
			Run_Intro
		}

		#Set Nice to +10 (not critical)
		renice -n 10 $$ &> /dev/null

		#Start display updates
		while true
		{

			if (( $BLANK_SCREEN_AT_SPECIFIC_TIME_ENABLED )) {

				RUN_BLANK_SCREEN_AT_SPECIFIC_TIME

			}

			#Disable updates when screen is blanked
			if (( $BLANK_SCREEN_ACTIVE )) {

				sleep 60

			#Update enabled scenes
			} else {

				if (( ${aEnabledScenes[$SCENE_CURRENT]} )) {

					Update_Banner

					# - Input mode scene update (storage array)
					if (( $SCENE_CURRENT == 1 )) {

						Update_Scene_1 0 1

					# - Input mode scene update (storage array)
					} elif (( $SCENE_CURRENT == 2 )) {

						Update_Scene_1 2 3

					# - Input mode scene update (storage array)
					} elif (( $SCENE_CURRENT == 3 )) {

						Update_Scene_1 4 5

					# - Normal scene update
					} else {

						Update_Scene_$SCENE_CURRENT

					}

					#Apply refresh rate delay
					sleep $REFRESH_RATE

				}

				#Scene Switcher
				((SCENE_CURRENT++))

				#Cap
				if (( $SCENE_CURRENT >= $MAX_SCENES )) {
					setvar SCENE_CURRENT = '0'
				}


			}

		}
	}

	#-----------------------------------------------------------------------------------
	#Clean up temp files
	rm $FP_TEMP &> /dev/null
	#-----------------------------------------------------------------------------------
	#Delete[] Global arrays
	unset aCOLOUR
	unset aEnabledScenes
	Destroy_STORAGE
	#-----------------------------------------------------------------------------------
	exit
	#-----------------------------------------------------------------------------------
}