#!/bin/bash
do {
	#////////////////////////////////////
	# DietPi-Globals
	#
	#////////////////////////////////////
	# Created by Daniel Knight / daniel.knight@dietpi.com / dietpi.com
	#
	#////////////////////////////////////
	#
	# Info:
	# - Allows export of shared DietPi global variables/funcs into current bash session, and other scripts
	#
	# Excluded scripts, which do NOT load these globals
	# - dietpi-ramlog
	# - dietpi-ramdisk
	# - dietpi.txt (and all other .txt .ini or config files)
	#
	#////////////////////////////////////

	#-----------------------------------------------------------------------------------
	# Core var's, functions, environment. Used at start of all scripts.
	#-----------------------------------------------------------------------------------
	#Prevent incorrect parsing with non-english locales.
	setvar LANG = 'en_GB.UTF-8'

	#Ensure we are in users home dir: https://github.com/Fourdee/DietPi/issues/905#issuecomment-298223705
	cd $HOME

	#To be exported by the originating script (eg: dietpi-software)
	# - Used in:
	#	G_ERROR_ (info)
	setvar G_PROGRAM_NAME = ''''

	#User input? (eg: interactive shell available via STDIN check)
	#	Effects:
	#	 - G_ERROR_HANDLER whiptail display
	#	NB: You can export G_USER_INPUTS=0 to force non-interactive (eg: .bashrc) Must run 'unset G_USER_INPUTS' after to return to auto detection.
	if test -z $G_USER_INPUTS {

		setvar G_USER_INPUTS = '0'

		if [[ -t 0 ]] {

			#checked:
			#	- OK | systemD = non-STDIN
			#	- OK | Cron = non-STDIN

			#shopt login_shell # == [[ $- == *i* ]] #.bashrc dietpi/login exec is not interactive...
			#[ -t 0 ]# .bashrc dietpi/login exec is interactive...
			#set -i in .bashrc is not available...

			setvar G_USER_INPUTS = '1'

		}

	}

	#DEBUG:
	# echo $G_USER_INPUTS
	# shopt login_shell
	# sleep 1
	#DEBUG:

	# - DietPi Scripts, moved from /etc/bash.bashrc
	alias sudo='sudo ' # https://github.com/Fourdee/DietPi/issues/424
	alias dietpi-process_tool='/DietPi/dietpi/dietpi-process_tool'
	alias dietpi-letsencrypt='/DietPi/dietpi/dietpi-letsencrypt'
	alias dietpi-autostart='/DietPi/dietpi/dietpi-autostart'
	alias dietpi-cron='/DietPi/dietpi/dietpi-cron'
	alias dietpi-launcher='/DietPi/dietpi/dietpi-launcher'
	alias dietpi-cleaner='/DietPi/dietpi/dietpi-cleaner'
	alias dietpi-morsecode='/DietPi/dietpi/dietpi-morsecode'
	alias dietpi-sync='/DietPi/dietpi/dietpi-sync'
	alias dietpi-backup='/DietPi/dietpi/dietpi-backup'
	alias dietpi-bugreport='/DietPi/dietpi/dietpi-bugreport'
	alias dietpi-services='/DietPi/dietpi/dietpi-services'
	alias dietpi-config='/DietPi/dietpi/dietpi-config'
	alias dietpi-software='/DietPi/dietpi/dietpi-software'
	alias dietpi-update='/DietPi/dietpi/dietpi-update'
	alias dietpi-drive_manager='/DietPi/dietpi/dietpi-drive_manager'
	alias emulationstation='/opt/retropie/supplementary/emulationstation/emulationstation'

	alias cpu='/DietPi/dietpi/dietpi-cpuinfo'
	alias dietpi-logclear='/DietPi/dietpi/dietpi-logclear'

	# - Optional DietPi software aliases/functions
	test -f /usr/local/games/opentyrian/run && alias opentyrian='/usr/local/games/opentyrian/run'
	test -f /DietPi/dietpi/misc/dietpi-justboom && alias dietpi-justboom='/DietPi/dietpi/misc/dietpi-justboom'
	test -f "$G_FP_DIETPI_USERDATA"/dxx-rebirth/run.sh && alias dxx-rebirth="$G_FP_DIETPI_USERDATA/dxx-rebirth/run.sh"
	test -f /usr/share/applications/kodi.desktop && alias startkodi='/DietPi/dietpi/misc/start_kodi'
	test -f /etc/systemd/system/dietpi-cloudshell.service && alias dietpi-cloudshell='/DietPi/dietpi/dietpi-cloudshell'
	# occ/ncc need to be global function, as aliases are not accessible from non-interactive scripts:
	test -f /var/www/owncloud/occ && proc occ { sudo -u www-data php /var/www/owncloud/occ @ARGV; }
	test -f /var/www/nextcloud/occ && proc ncc { sudo -u www-data php /var/www/nextcloud/occ @ARGV; }

	# - Treesize
	#	$1 = Optional input directory (eg: G_TREESIZE /etc/apt)
	proc G_TREESIZE {

		du -k --max-depth=1 $1 | sort -nr | awk '
		BEGIN {
			split("KB,MB,GB,TB", Units, ",");
		}
		{
			u = 1;
			while ($1 >= 1024)
			{
				$1 = $1 / 1024;
				u += 1;
			}
			$1 = sprintf("%.1f %s", $1, Units[u]);
			print $0;
		}
		'
	}

	# DietPi-Notify
	# $1:
	#	-2=process animation
	#	- $2 = text
	#	-1=autodetect_fail_ok
	#	- $2 = EXIT_CODE
	#	0=OK
	#	- $2 = text
	#	1=failed
	#	- $2 = text
	#	2=info
	#	- $2 = text
	#	3=DietPi banner style
	#	- $2 = txt program name
	#	- $3 = txt mode
	proc G_DIETPI-NOTIFY {

		local ainput_string=("$@")

		#header_line="\e[38;5;154m─────────────────────────────────────────────────────\e[0m"
		local header_line="\e[90m─────────────────────────────────────────────────────\e[0m"

		local status_text_ok="\e[32m  OK  \e[0m"
		local status_text_error="\e[31mFAILED\e[0m"
		local status_text_info="\e[0m INFO \e[0m"

		local bracket_string_l="\e[90m[\e[0m"
		local bracket_string_r="\e[90m]\e[0m"

		#Funcs

		proc Print_Process_Animation {

			local bright_dot="\e[1;93m.\e[0m"
			local dimmed_dot="\e[2;33m.\e[0m"
			local aprocess_string=(
				#\u23F9
				"$bright_dot     "
				"$dimmed_dot$bright_dot    "
				" $dimmed_dot$bright_dot   "
				"  $dimmed_dot$bright_dot  "
				"   $dimmed_dot$bright_dot "
				"    $dimmed_dot$bright_dot"
				"    $bright_dot$dimmed_dot"
				"   $bright_dot$dimmed_dot "
				"  $bright_dot$dimmed_dot  "
				" $bright_dot$dimmed_dot   "
				"$bright_dot$dimmed_dot    "
			)

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

				(( i == 11 )) && i=1
				[ -f /tmp/dietpi-process.pid ] && echo -ne "\r$bracket_string_l${aprocess_string[i]}$bracket_string_r " || break
				sleep 0.15

			done

		}

		proc Clean_Process_Animation {

			if test -f /tmp/dietpi-process.pid {

				kill $(</tmp/dietpi-process.pid) &> /dev/null
				rm /tmp/dietpi-process.pid &> /dev/null || sudo rm /tmp/dietpi-process.pid &> /dev/null
				# In case, the output took more than one line, clean from cursor (animation position) until end of terminal.
				tput ed

			}
			echo -ne "\r\e[K"

		}

		proc Print_Process {

			echo -ne "\r\e[9C"

		}

		proc Print_Ok {

			Clean_Process_Animation
			echo -ne "$bracket_string_l$status_text_ok$bracket_string_r "

		}

		proc Print_Failed {

			Clean_Process_Animation
			echo -ne "$bracket_string_l$status_text_error$bracket_string_r "

		}

		proc Print_Info {

			Clean_Process_Animation
			echo -ne "$bracket_string_l$status_text_info$bracket_string_r "

		}

		# - Print all input string on same line
		# - $1 = start printing from word number $1
		proc Print_Input_String {

			local i=0
			for (( i=$1;i<${#ainput_string[@]} ;i++))
			do
				echo -ne "${ainput_string[$i]}"
			done

		}

		#--------------------------------------------------------------------------------------
		# Main Loop
		#--------------------------------------------------------------------------------------
		#Exit code, print OK or Failed
		#$2 = exit code
		# - Use this at end of DietPi scripts, EG: G_DIETPI-NOTIFY -1 ${EXIT_CODE:=0}
		if (( $1 == -1 )) {

			if test $2 = "0" {

				setvar ainput_string = ''(" Completed")
				Print_Ok
				Print_Input_String 2
				echo ''

			} else {

				setvar ainput_string = ''(" An issue has occured")
				Print_Failed
				Print_Input_String 2
				echo ''

			}

		#--------------------------------------------------------------------------------------
		#Status Processing
		#$@ = txt desc
		} elif (( $1 == -2 )) {

			Print_Process
			Print_Input_String 1
			# Calculate the amount of output lines and in case move cursor up for correct animation and to allow cleaning the whole output.
			local string="$[join(ARGV)]"
			local lines=0 {

				tput cuu1
				(( lines-- ))

			}
			test ! -f /tmp/dietpi-process.pid && touch /tmp/dietpi-process.pid && shell { Print_Process_Animation & echo $! > /tmp/dietpi-process.pid }

		#Status Ok
		#$@ = txt desc
		} elif (( $1 == 0 )) {

			Print_Ok
			Print_Input_String 1
			echo ''

		#Status failed
		#$@ = txt desc
		} elif (( $1 == 1 )) {

			Print_Failed
			Print_Input_String 1
			echo ''

		#Status Info
		#$@ = txt desc
		} elif (( $1 == 2 )) {

			Print_Info
			echo -ne "\e[90m"
			Print_Input_String 1
			echo -e "\e[0m"

		#DietPi banner style
		#$2 = txt program name
		#$3 = txt mode
		} elif (( $1 == 3 )) {

			echo -e "\n \e[38;5;154m$2\e[0m"
			echo -e $header_line
			echo -e " \e[90mMode: \e[0m$(Print_Input_String 2)\n"

		}
		#-----------------------------------------------------------------------------------
		# Unset also internal functions, otherwise they are accessible from terminal.
		unset Print_Process_Animation
		unset Clean_Process_Animation
		unset Print_Process
		unset Print_Ok
		unset Print_Failed
		unset Print_Info
		unset Print_Input_String
		#-----------------------------------------------------------------------------------

	}

	setvar G_CHECK_ROOT_USER_VERIFIED = ${G_CHECK_ROOT_USER_VERIFIED:=0} #only check once for each session
	proc G_CHECK_ROOT_USER {

		if (( ! $G_CHECK_ROOT_USER_VERIFIED )) {

			G_DIETPI-NOTIFY -2 'Checking for (elevated) root access'

			if (( $UID != 0 )) {

				G_DIETPI-NOTIFY 1 'Root privileges required. Please run the command with "sudo"\n'
				exit 1

			} else {

				G_DIETPI-NOTIFY 0 'Root access verified.'
				export G_CHECK_ROOT_USER_VERIFIED=1

			}

		}

	}

	setvar G_CHECK_ROOTFS_RW_VERIFIED = ${G_CHECK_ROOTFS_RW_VERIFIED:=0} #only check once for each session
	proc G_CHECK_ROOTFS_RW {

		if (( ! $G_CHECK_ROOTFS_RW_VERIFIED )) {

			#RootFS RW check
			/DietPi/dietpi/dietpi-drive_manager 3
			if (( $? != 0 )) {

				G_DIETPI-NOTIFY 1 'RootFS is currently Read Only, unable to continue.\n'
				exit 1

			} else {

				export G_CHECK_ROOTFS_RW_VERIFIED=1

			}

		}

	}

	#-----------------------------------------------------------------------------------
	# DietPi Error Handler
	# https://github.com/Fourdee/DietPi/issues/1311#issuecomment-353716344
	#-----------------------------------------------------------------------------------
	setvar G_ERROR_HANDLER_EXITCODE = ''''					#input value to use with G_ERROR_HANDLER
	setvar G_ERROR_HANDLER_COMMAND = ''''					#eg: G_AGI: moooooooo
	#	For export: On error, following entries will be used
	setvar G_ERROR_HANDLER_ONERROR_EXIT = '1'				#Do we exit the program when the error occurs? 0=no 1=yes
	setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = ''''		#FP to logfile, if available

	#Runs automatically after G_ERROR_HANDLER to reset vars to default
	proc G_ERROR_HANDLER_RESET {

		#unset originating program
		unset G_ERROR_HANDLER_EXITCODE
		unset G_ERROR_HANDLER_COMMAND

		unset G_ERROR_HANDLER_ONERROR_EXIT
		unset G_ERROR_HANDLER_ONERROR_FPLOGFILE

		setvar G_ERROR_HANDLER_EXITCODE = ''''
		setvar G_ERROR_HANDLER_COMMAND = ''''

		setvar G_ERROR_HANDLER_ONERROR_EXIT = '1'
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = ''''

	}

	#Handles exit code errors, as defined by G_ERROR_HANDLER_xxxx settings
	#	Usage:
	#		export G_ERROR_HANDLER_COMMAND='Doing something usefull with Owncloud'
	#		export G_ERROR_HANDLER_ONERROR_EXIT=0 # Don't exit program on error, continue
	#		export G_ERROR_HANDLER_ONERROR_FPLOGFILE=/var/log/mylogfile # to print if error occurs
	#		occ --doing-something-useful
	#		export G_ERROR_HANDLER_EXITCODE=$?
	#		G_ERROR_HANDLER
	proc G_ERROR_HANDLER {

		#Ok
		if (( $G_ERROR_HANDLER_EXITCODE == 0 )) {

			G_DIETPI-NOTIFY 0 $G_ERROR_HANDLER_COMMAND

		#Error
		} else {

			local print_hw_info="VERSION:v$(sed -n 1p /DietPi/dietpi/.version).$(sed -n 2p /DietPi/dietpi/.version) | HW_MODEL:$G_HW_MODEL | HW_ARCH:$G_HW_ARCH | DISTRO:$G_DISTRO"
			local print_exitcode_info="exit_code = $G_ERROR_HANDLER_EXITCODE"
			local print_logfile_info="Log file contents:\n$(tail -50 $G_ERROR_HANDLER_ONERROR_FPLOGFILE)"
			local print_report_to_dietpi_info='If problems persist, please report this to DietPi for investigation, including a screenshot of this error! (https://github.com/Fourdee/DietPi/issues).'
			local print_unable_to_continue='Unable to continue, the program will now terminate.'

			echo ''
			if test -n $G_PROGRAM_NAME {

				G_DIETPI-NOTIFY 1 "$G_PROGRAM_NAME: $G_ERROR_HANDLER_COMMAND"

			} else {

				G_DIETPI-NOTIFY 1 $G_ERROR_HANDLER_COMMAND

			}

			G_DIETPI-NOTIFY 2 $print_exitcode_info
			G_DIETPI-NOTIFY 2 $print_hw_info

			# - On Error: Display logfile FP, if set
			if test -n $G_ERROR_HANDLER_ONERROR_FPLOGFILE {

				G_DIETPI-NOTIFY 2 $print_logfile_info

			}

			#	Display "please report to dietpi", if its one of our programs
			if test -n $G_PROGRAM_NAME {

				G_DIETPI-NOTIFY 2 $print_report_to_dietpi_info

			}

			# - On Error: Display whip version?
			if (( $G_USER_INPUTS )) {

				local whip_msg=()
				if test -n $G_PROGRAM_NAME {

					setvar whip_msg = ""$G_PROGRAM_NAME: $G_ERROR_HANDLER_COMMAND""

				} else {

					setvar whip_msg = "$G_ERROR_HANDLER_COMMAND"

				}

				setvar whip_msg = ''\n''
				setvar whip_msg = "" - $print_exitcode_info""
				setvar whip_msg = ''\n''
				setvar whip_msg = "" - $print_hw_info""
				setvar whip_msg = ''\n\n''

				#	Display optional logfile?
				if test -n $G_ERROR_HANDLER_ONERROR_FPLOGFILE {

					setvar whip_msg = "$print_logfile_info"
					setvar whip_msg = ''\n\n''

				}

				#	Display "please report to dietpi", if its one of our programs
				if test -n $G_PROGRAM_NAME {

					setvar whip_msg = "$print_report_to_dietpi_info"

				}

				if (( $G_ERROR_HANDLER_ONERROR_EXIT )) {

					setvar whip_msg = ''\n\n''
					setvar whip_msg = "$print_unable_to_continue"

				}

				whiptail --title 'DietPi Error Handler:' --msgbox $whip_msg --scrolltext 22 85

			}

			# - On Error: Kill current script, excluding the shell.
			if (( $G_ERROR_HANDLER_ONERROR_EXIT )) {

			# - Github printout:
			echo -e "
\e[41m
--------------------------------------------------------------------
- DietPi has encounted an error, and, is unable to continue        -
- Please create a ticket: https://github.com/Fourdee/DietPi/issues -
- Copy and paste the BLUE lines below, into the ticket             -
--------------------------------------------------------------------
\e[0m
\e[44m
#### Required Information:
- DietPi Version | v$(sed -n 1p /DietPi/dietpi/.version).$(sed -n 2p /DietPi/dietpi/.version)
- SBC Device     | $G_HW_MODEL_DESCRIPTION (index=$G_HW_MODEL)
- Distro         | $G_DISTRO_NAME (index=$G_DISTRO)
- Command        | $G_ERROR_HANDLER_COMMAND
- Error Handler  | G_ERROR_HANDLER

#### Additional Information (if applicable):
- Software title | $G_PROGRAM_NAME

#### Expected behaviour:
<!-- What SHOULD be happening? -->

#### Actual behaviour:
<!-- What IS happening? -->

#### Steps to reproduce:
<!-- Explain how to reproduce the issue -->

#### Additional logs:
\`\`\`
$print_logfile_info
\`\`\`
\e[0m

\e[41m--------------------------------------------------------------------\e[0m
"

				G_DIETPI-NOTIFY 1 $print_unable_to_continue

				# - Reset for next run
				G_ERROR_HANDLER_RESET

				kill -INT $$

			}

		}

		return $G_ERROR_HANDLER_EXITCODE

		# - Reset for next run
		G_ERROR_HANDLER_RESET

	}

	#Run a command and send the output through the error handler. This has the same effect as running G_ERROR_HANDLER afterwards, however, allows for command used info, and log output/view when an error occurs
	#NB: This command does not support inputs with redirects. For file creation, use G_FILE_EXISTS afterwards to check it exists: https://github.com/Fourdee/DietPi/issues/1311#issuecomment-354541417
	#	$@ = input command
	#	eg:
	#		G_RUN_CMD mkdir /never/gonna/work
	proc G_RUN_CMD {

		setvar G_ERROR_HANDLER_COMMAND = "@ARGV"

		G_DIETPI-NOTIFY -2 "Running command: $G_ERROR_HANDLER_COMMAND"

		$G_ERROR_HANDLER_COMMAND &> /tmp/G_ERROR_HANDLER_COMMAND
		setvar G_ERROR_HANDLER_EXITCODE = ""$?
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = ''/tmp/G_ERROR_HANDLER_COMMAND''

		G_ERROR_HANDLER

		rm /tmp/G_ERROR_HANDLER_COMMAND &> /dev/null

	}

	#Checks if a file/folder exists
	#	Automatically passed through G_ERROR_HANDLER
	proc G_FILE_EXISTS {

		setvar G_ERROR_HANDLER_COMMAND = "@ARGV"
		setvar G_ERROR_HANDLER_EXITCODE = '0'

		G_DIETPI-NOTIFY -2 "Checking for existance: $G_ERROR_HANDLER_COMMAND"

		local string=''

		if test -f $G_ERROR_HANDLER_COMMAND {

			setvar string = ""File exists""

		} elif test -d $G_ERROR_HANDLER_COMMAND {

			setvar string = ""Folder exists""

		} else {

			setvar string = ""File/folder does not exist""
			setvar G_ERROR_HANDLER_EXITCODE = '1'

		}

		setvar string = "" | $G_ERROR_HANDLER_COMMAND""

		echo -e $string > /tmp/G_ERROR_HANDLER_COMMAND
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = ''/tmp/G_ERROR_HANDLER_COMMAND''
		setvar G_ERROR_HANDLER_COMMAND = "$string"

		G_ERROR_HANDLER

		rm /tmp/G_ERROR_HANDLER_COMMAND &> /dev/null

	}

	#-----------------------------------------------------------------------------------
	# DietPi First-Run Stage
	#-----------------------------------------------------------------------------------
	# -2 = PREP_SYSTEM/Unknown | -1 = first boot | 0 = run dietpi-software at login | 1 = completed
	setvar G_DIETPI_INSTALL_STAGE = '-2'
	if test -f /DietPi/dietpi/.install_stage {

		setvar G_DIETPI_INSTALL_STAGE = $(cat /DietPi/dietpi/.install_stage)

	}

	#-----------------------------------------------------------------------------------
	# Hardware Details
	#-----------------------------------------------------------------------------------
	setvar G_HW_MODEL = ${G_HW_MODEL:-0}
	setvar G_HW_MODEL_DESCRIPTION = ${G_HW_MODEL_DESCRIPTION:-NULL}
	setvar G_HW_ARCH = ${G_HW_ARCH:-0}
	setvar G_HW_CPU_CORES = ${G_HW_CPU_CORES:-1}
	setvar G_HW_CPUID = ${G_HW_CPUID:-0}

	setvar G_DISTRO = ${G_DISTRO:-0}
	setvar G_DISTRO_NAME = ${G_DISTRO_NAME:-NULL}

	# - Update
	#	NB: dietpi-boot service launches dietpi-obtain_hw_model to create the following file
	if test -f /DietPi/dietpi/.hw_model {

		setvar G_HW_MODEL = $(sed -n 1p /DietPi/dietpi/.hw_model)
		setvar G_HW_MODEL_DESCRIPTION = $(sed -n 2p /DietPi/dietpi/.hw_model)
		setvar G_HW_ARCH = $(sed -n 6p /DietPi/dietpi/.hw_model)
		setvar G_HW_CPU_CORES = $(nproc --all)
		setvar G_HW_CPUID = $(sed -n 9p /DietPi/dietpi/.hw_model)

		setvar G_DISTRO = $(sed -n 3p /DietPi/dietpi/.hw_model)
		setvar G_DISTRO_NAME = ''jessie''
		if (( $G_DISTRO == 4 )) {

			setvar G_DISTRO_NAME = ''stretch''

		} elif (( $G_DISTRO == 5 )) {

			setvar G_DISTRO_NAME = ''buster''

		}

	}

	#Returns current CPU temp 'C
	proc G_OBTAIN_CPU_TEMP {

		# - Array to store possible locations for temp read.
		setvar afp_temperature = ''(

			#'/sys/class/thermal/thermal_zone1/temp' #sparky/Asus, will break other SBC temp readouts as most have 2 zones, needs a special case
			'/sys/class/thermal/thermal_zone0/temp'
			'/sys/devices/platform/sunxi-i2c.0/i2c-0/0-0034/temp1_input'
			'/sys/class/hwmon/hwmon0/device/temp_label'

		)

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

			if [ -f "${afp_temperature[$i]}" ]; then

				#	Sparky/asus, special case:
				if (( $G_HW_MODEL == 70 || $G_HW_MODEL == 52 )); then

					cpu_temp_current=$(cat /sys/class/thermal/thermal_zone1/temp)

				else

					cpu_temp_current=$(cat ${afp_temperature[$i]})

				fi

				# - Boards that provide 2 digit output
				#	Pine
				# 	NanoPi M2
				#	NanoPi M3
				#	H3 3.x
				#	H2+ 3.x
				if (( $G_HW_MODEL == 40 ||
					$G_HW_MODEL == 61 ||
					$G_HW_MODEL == 62 ||
					( $G_HW_CPUID == 1 && $(uname -r | grep -ci -m1 '^3.') ) ||
					( $G_HW_MODEL == 32 && $(uname -r | grep -ci -m1 '^3.') ) )); then

					echo -e "Do nothing" &> /dev/null

				else

					cpu_temp_current=$( echo -e "$cpu_temp_current" | awk '{print $1/1000}' | xargs printf "%0.0f" )

				fi


				break

			fi

		done

		unset afp_temperature

		echo $cpu_temp_current

	}

	#Returns current CPU usage %
	proc G_OBTAIN_CPU_USAGE {

		# - PS (inaccurate, but fast??)
		local cpu_usage=0
		local fp_temp='/tmp/.cpu_usage_cpuinfo'
		ps -axo %cpu | sed '1d' | sed 's/ //' > "$fp_temp"
		while read 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=1;$cpu_usage / $(nproc --all)" | bc -l )

		echo $cpu_usage

	}

	#-----------------------------------------------------------------------------------
	# DietPi specific directories
	#-----------------------------------------------------------------------------------
	# - Default DietPi userdata location. This must NEVER change.
	setvar G_FP_DIETPI_USERDATA = ''/mnt/dietpi_userdata''
	# - Current DietPi userdata location (actual, follows symlink of G_FP_DIETPI_USERDATA, if not on rootFS)
	#G_FP_DIETPI_USERDATA_CURRENT=$(readlink -f $G_FP_DIETPI_USERDATA)
	#FP_DIETPI_VAR_LIB='/var/lib/dietpi'
	#FP_DIETPI_VAR_TMP='/var/tmp/dietpi'

	#-----------------------------------------------------------------------------------
	# URL Connection test
	#-----------------------------------------------------------------------------------
	# $@ = URL
	#	NB: automatically error handled (G_ERROR_HANDLER)
	#	Prompts user to configure network if $G_USER_INPUTS=1
	proc G_CHECK_URL {

		local string="$[join(ARGV)]"
		local timeout=10
		local retry_max=5
		local error_connection_failed=0

		setvar G_ERROR_HANDLER_EXITCODE = '0'
		setvar G_ERROR_HANDLER_COMMAND = ""Connection test: $string""
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = ''/tmp/G_CHECK_URL''

		while true
		{

			#Allow user choice to configure network on failure
			if (( $G_USER_INPUTS )) {

				setvar G_ERROR_HANDLER_ONERROR_EXIT = '0'

				if (( $error_connection_failed )) {

					#Ask to check settings,
					whiptail --title "URL Connection Test Failed" --yesno "DietPi was unable to establish a connection:\n - $string\n\nIf problems persist, the URL may be offline/unreachable.\n\nWould you like to configure network settings and try again?" --yes-button "Ok" --no-button "Exit" --defaultno --backtitle $G_PROGRAM_NAME 15 80
					setvar CHOICE = ""$?

					#run dietpi config
					if (( $CHOICE == 0 )) {

						whiptail --title "Launching DietPi-Config" --msgbox "DietPi-Config will now be started.\nUse the Network Options menu to change and test your network settings.\n\nWhen completed, exit DietPi-Config to resume." --backtitle "Launching DietPi-Config" 14 60
						/DietPi/dietpi/dietpi-config 8 1

					#User aborted, exit now with current error information
					} else {

						setvar G_ERROR_HANDLER_ONERROR_EXIT = '1'
						setvar G_ERROR_HANDLER_EXITCODE = '1'
						setvar G_USER_INPUTS = '0' #disable whiptail info
						G_ERROR_HANDLER
						#break #handled by G_ERROR_HANDLER script kill

					}

				}

			#Force exit on failure to end loop (overrides any export G_ERROR_HANDLER_ONERROR_EXIT in this session)
			} else {

				setvar G_ERROR_HANDLER_ONERROR_EXIT = '1'

			}

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

				G_DIETPI-NOTIFY -2 "($i/$retry_max) Testing connection to $string, please wait..."

				wget --spider --timeout=$timeout --tries=1 "$string" &> /tmp/G_CHECK_URL
				G_ERROR_HANDLER_EXITCODE=$?
				#	Valid
				if (( $G_ERROR_HANDLER_EXITCODE == 0 )); then

					break

				#	Retry
				else

					sleep 2
					error_connection_failed=1
					G_DIETPI-NOTIFY -2 "Failed connection attempt ($i/$retry_max), retrying..."

				fi

			done

			#--no-check-certificate
			#https://github.com/Fourdee/DietPi/issues/352#issuecomment-221013166

			G_ERROR_HANDLER
			if (( $G_ERROR_HANDLER_EXITCODE == 0 )) {

				break

			}

		}

		rm /tmp/G_CHECK_URL

		return $G_ERROR_HANDLER_EXITCODE

	}

	#-----------------------------------------------------------------------------------
	# APT
	#-----------------------------------------------------------------------------------
	setvar G_FP_LOG_APT = ''/var/tmp/dietpi/logs/dietpi-software_apt.log''

	#Support for apt-fast: https://github.com/Fourdee/DietPi/issues/698
	# APT_BINARY='apt-get'
	# if [ -f /usr/bin/apt-fast ]; then

		# APT_BINARY='apt-fast'

	# fi

	#apt-get install
	#	NB: automatically error handled (G_ERROR_HANDLER)
	proc G_AGI {

		local string="$[join(ARGV)]"
		local force_options=''

		if (( $G_DISTRO >= 4 )) {

			setvar force_options = ''--allow-downgrades --allow-remove-essential --allow-change-held-packages --allow-unauthenticated''

		} else {

			setvar force_options = ''--force-yes''

		}

		setvar G_ERROR_HANDLER_EXITCODE = '0'
		setvar G_ERROR_HANDLER_COMMAND = ""G_AGI: $string""
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = "$G_FP_LOG_APT"


		#-qq can add a slight period of appearing nothing is happening, lets inform user
		G_DIETPI-NOTIFY 2 "APT installation for: $string, please wait...'"

		DEBIAN_FRONTEND=noninteractive' apt-get install -y -qq $force_options $string 2>&1 | tee $G_FP_LOG_APT
		setvar G_ERROR_HANDLER_EXITCODE = ${PIPESTATUS[0]}

		G_ERROR_HANDLER

		return $G_ERROR_HANDLER_EXITCODE

	}

	#apt-get purge
	#	NB: automatically error handled (G_ERROR_HANDLER)
	proc G_AGP {

		local string="$[join(ARGV)]"
		local options=''
		if (( $G_DISTRO >= 4 )) {

			setvar options = '' --allow-change-held-packages''

		}

		setvar G_ERROR_HANDLER_EXITCODE = '0'
		setvar G_ERROR_HANDLER_COMMAND = ""G_AGP: $string""
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = "$G_FP_LOG_APT"

		G_DIETPI-NOTIFY 2 "APT removal for: $string, please wait...'"

		DEBIAN_FRONTEND=noninteractive' apt-get purge -y $string $options 2>&1 | tee $G_FP_LOG_APT
		setvar G_ERROR_HANDLER_EXITCODE = ${PIPESTATUS[0]}

		G_ERROR_HANDLER

		return $G_ERROR_HANDLER_EXITCODE

	}

	#apt-get autoremove
	#	NB: automatically error handled (G_ERROR_HANDLER)
	proc G_AGA {

		setvar G_ERROR_HANDLER_EXITCODE = '0'
		setvar G_ERROR_HANDLER_COMMAND = ""G_AGA""
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = "$G_FP_LOG_APT"

		G_DIETPI-NOTIFY 2 "APT autoremove + purge, please wait...'"

		DEBIAN_FRONTEND=noninteractive' apt-get autoremove --purge -y  2>&1 | tee $G_FP_LOG_APT
		setvar G_ERROR_HANDLER_EXITCODE = ${PIPESTATUS[0]}

		G_ERROR_HANDLER

		return $G_ERROR_HANDLER_EXITCODE

	}

	#apt-get install -f
	#	NB: automatically error handled (G_ERROR_HANDLER)
	proc G_AGF {

		setvar G_ERROR_HANDLER_EXITCODE = '0'
		setvar G_ERROR_HANDLER_COMMAND = ""G_AGF""
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = "$G_FP_LOG_APT"

		G_DIETPI-NOTIFY 2 "APT fix, please wait...'"

		DEBIAN_FRONTEND=noninteractive' apt-get install -f -y 2>&1 | tee $G_FP_LOG_APT
		setvar G_ERROR_HANDLER_EXITCODE = ${PIPESTATUS[0]}

		G_ERROR_HANDLER

		return $G_ERROR_HANDLER_EXITCODE

	}

	#apt-get update
	#	NB: automatically error handled (G_ERROR_HANDLER)
	proc G_AGUP {

		setvar G_ERROR_HANDLER_EXITCODE = '0'
		setvar G_ERROR_HANDLER_COMMAND = ""G_AGUP""
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = "$G_FP_LOG_APT"

		G_DIETPI-NOTIFY 2 "APT update, please wait...'"

		DEBIAN_FRONTEND=noninteractive' apt-get clean 2>&1 | tee $G_FP_LOG_APT'
		DEBIAN_FRONTEND=noninteractive' apt-get update 2>&1 | tee -a $G_FP_LOG_APT
		setvar G_ERROR_HANDLER_EXITCODE = ${PIPESTATUS[0]}

		G_ERROR_HANDLER

		return $G_ERROR_HANDLER_EXITCODE

	}

	#apt-get upgrade
	#	NB: automatically error handled (G_ERROR_HANDLER)
	proc G_AGUG {

		setvar G_ERROR_HANDLER_EXITCODE = '0'
		setvar G_ERROR_HANDLER_COMMAND = ""G_AGUG""
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = "$G_FP_LOG_APT"

		G_DIETPI-NOTIFY 2 "APT upgrade, please wait...'"

		DEBIAN_FRONTEND=noninteractive' apt-get upgrade -y 2>&1 | tee $G_FP_LOG_APT
		setvar G_ERROR_HANDLER_EXITCODE = ${PIPESTATUS[0]}

		G_ERROR_HANDLER

		return $G_ERROR_HANDLER_EXITCODE

	}

	#apt-get dist-upgrade
	#	NB: automatically error handled (G_ERROR_HANDLER)
	proc G_AGDUG {

		setvar G_ERROR_HANDLER_EXITCODE = '0'
		setvar G_ERROR_HANDLER_COMMAND = ""G_AGDUG""
		setvar G_ERROR_HANDLER_ONERROR_FPLOGFILE = "$G_FP_LOG_APT"

		if (( $G_DISTRO >= 4 )) {

			setvar force_options = ''--allow-downgrades --allow-remove-essential --allow-change-held-packages --allow-unauthenticated''

		} else {

			setvar force_options = ''--force-yes''

		}

		G_DIETPI-NOTIFY 2 "APT dist-upgrade, please wait...'"

		DEBIAN_FRONTEND=noninteractive' apt-get dist-upgrade -y 2>&1 | tee $G_FP_LOG_APT
		setvar G_ERROR_HANDLER_EXITCODE = ${PIPESTATUS[0]}

		G_ERROR_HANDLER

		return $G_ERROR_HANDLER_EXITCODE

	}

	#Checks for required APT packages, installs if needed.
	# $@ = list of required packages
	#	NB: automatically error handled (G_ERROR_HANDLER)
	proc G_AG_CHECK_INSTALL_PREREQ {

		local fp_temp='/tmp/.G_AG_CHECK_INSTALL_PREREQ'
		local exit_code=0
		local string=( "$@" )
		local packages_to_install=''

		G_DIETPI-NOTIFY 2 "Checking for pre-req APT packages: ${string[*]}"

		dpkg --get-selections > "$fp_temp"
		for i in "${string[@]}"
		{

			if (( ! $(grep -ci -m1 "^$i[[:space:]]" "$fp_temp") )) {

				G_DIETPI-NOTIFY 2 "($i) | Not found, flagged for installation"
				setvar packages_to_install = "" $i""

			}

		}

		if test -n $packages_to_install {

			G_DIETPI-NOTIFY -2 "Installing pre-req APT packages"
			G_AGI $packages_to_install
			setvar exit_code = ""$?

		} else {

			G_DIETPI-NOTIFY 2 "Pre-req APT packages are installed"

		}

		#G_AGI now handles the error

		rm $fp_temp

		return $exit_code

	}

	#-----------------------------------------------------------------------------------
	# HW specific
	#-----------------------------------------------------------------------------------
	#rpi-update
	#	- Holds APT packages
	#	- Skips backup
	proc G_RPI_UPDATE {

		if (( $G_HW_MODEL < 10 )) {

			G_AG_CHECK_INSTALL_PREREQ rpi-update
			export SKIP_BACKUP=1
			G_RUN_CMD rpi-update
			apt-mark hold raspberrypi-bootloader raspberrypi-kernel libraspberrypi-bin

		}

	}

	#-----------------------------------------------------------------------------------
	#G_DIETPI-NOTIFY 2 'DietPi-Globals loaded\n'
	#-----------------------------------------------------------------------------------

}