#!/bin/bash
#Reset error count and set as integer.
declare -i ELINE
declare -i ERR
ERR=0
declare -i WARN
WARNINGS=0
declare -i DISTANCE
DISTANCE=0
declare -i INFORMATION
INFOFORMATION=0
declare -i RR
RR=0
declare -i TT
TT=0
declare -i CALC
CALC=0
declare -i EXITCOL
EXITCOL=0

# Suppression?
SUPPRESS=$(echo "$*" | grep "suppress")
PROMPTSUPPRESSION=$(echo "$@" | grep "\-YES")

# Check for support of Repostorm

REPOSTORM=$(type -p repostorm)

# Terminal Detection & color
case "${TERM}" in
	"dumb");;
	*)
		COLUMNZ=$(tput cols)
		TXTRED=$(tput setaf 1)
		TXTBLD=$(tput bold)             # Bold
		TXTGRN=${TXTBLD}$(tput setaf 2) # bold green
		BLDBLU=${TXTBLD}$(tput setaf 4) # blue
		BLDWHT=${TXTBLD}$(tput setaf 7) # white
		YELLOW=$(tput setaf 3)			# yellow
		TXTRST=$(tput sgr0)             # Reset
		INFO="${BLDWHT}"		        # Feedback
		PASS="${BLDWHT}"*"${TXTRST}"
		WARNING="${TXTBLD}${YELLOW}"
		QUES="${BLDWHT}"?"${TXTRST}"
		BRIGHT=$(tput bold);;
esac

# Debug?
DEBUG=$(echo "$*" | grep -i "debug")

DATECURRENT=$(date +"%Y%m%d")
IPERF=$(type -p iperf3)

# Optional Network Data
ETHTOOL=$(type -p ethtool)

# Get Directory executed in.
CURRENT="${PWD}"

# check to see if notify is installed & if sound is supported.
NOTIFY=$(type -p notify-send)
SOUND=$(type -p canberra-gtk-play)

#Pull info we will use to compare against later
IUSER=${SUDO_USER:-$USER}
IHOME="/home/${IUSER}"

# Timer Declarations
declare -a STARTSECS=();
declare -a STOPSECS=();
#declare -a STARTS=();
#declare -a STOPS=();
declare -a OBJECT=();
declare -i TINDEX;

# DISK Operations? - Taking a stab at calculating disk / file sizes smartly up to Yottabyte
# Could easily roll up to a Geopbyte.
# · 1 Bit = Binary Digit
# · 8 Bits = 1 Byte
# · 1024 Bytes = 1 Kilobyte
# · 1024 Kilobytes = 1 Megabyte
# · 1024 Megabytes = 1 Gigabyte
# · 1024 Gigabytes = 1 Terabyte
# · 1024 Terabytes = 1 Petabyte
# · 1024 Petabytes = 1 Exabyte
# · 1024 Exabytes = 1 Zettabyte
# · 1024 Zettabytes = 1 Yottabyte
# · 1024 Yottabytes = 1 Brontobyte
# · 1024 Brontobytes = 1 Geopbyte

# See additional code in function FileSize to see how I did so using the array
# defined below.
declare -a DISKSIZES=("KB" "MB" "GB" "TB" "PB" "EB" "ZB" "YB")

finish () {
	if [[ "${DEBUG}" ]]; then
		echo "APPNAME:${APPNAME} | EUID: ${EUID} | USER: ${USER} | IUSER: ${IUSER} | ROOT: ${TRUEROOT} EXIT CODE: $?"
	fi
	if ! [[ "${SUPPRESS}" ]]; then
		Timer "Stop" "${APPNAME}"
		FullBar
	fi
}

# trap ctrl-c and call ctrl_c()
ctrl_c () {
		echo -en "\033[1G"
		echo -en "\033[1A\033[2K"
        Error "** Trapped CTRL-C, exiting."
		FullBar
		shopt -s extglob
        if [[ "${PWD}" == "/var/cache/apt/archives" ]]; then
            Encapsulate "Flushing bad package(s).  Please allow this to complete."
            find . -mindepth 1 ! -type d -regex 'partial\(/.*\)?' -delete
            rm "*.txt" 2>/dev/null
			if [[ -d ".debs/" ]]; then
				rm -R .debs/
			fi
        fi
		RUNNINGINSTANCES=$(ps -C apt-get | wc -l)
		if [[ "${RUNNINGINSTANCES}" -gt 1 ]]; then
			PID=$(pgrep apt-get)
			#echo "PID: $PID INSTANCES: ${RUNNINGINSTANCES}"
			CROAK=$(sudo killall -9 apt-get 2>/dev/null)
			while [[ -e "/proc/${PID}" ]]
			do
			    sleep .6
			done
		fi
		RUNNINGINSTANCES=$(ps -C repostorm | wc -l)
		if [[ "${RUNNINGINSTANCES}" -gt 1 ]]; then
			PID=$(pgrep repostorm)
			#echo "PID: $PID INSTANCES: ${RUNNINGINSTANCES}"
			CROAK=$(sudo killall -9 repostorm 2>/dev/null)
			while [[ -e "/proc/${PID}" ]]
			do
			    sleep .6
			done
		fi
		RUNNINGINSTANCES=$(ps -C uetheme | wc -l)
		if [[ "${RUNNINGINSTANCES}" -gt 1 ]]; then
			PID=$(pgrep uetheme)
			#echo "PID: $PID INSTANCES: ${RUNNINGINSTANCES}"
			SUPPRESS=$(sudo killall -9 uetheme 2>/dev/null)
			while [[ -e "/proc/${PID}" ]]
			do
			    sleep .6
			done
		fi
		if [[ "${DEBUG}" ]]; then
			echo "DEBUG: ${PWD}"
		fi
		if [[ -w "/var/cache/apt/archives/lock" ]]; then
		    Encapsulate "${PROGNAME}: Cleaning packages."
			FullBar
		    apt-get clean
		    apt-get autoclean
    	    FullBar
		fi
		exit 1;
}

# Dynamically display terminal window size
RedrawTerm () {
	clear
	if [[ "${DEBUG}" ]]; then
		echo "Width = $(tput cols) Height = $(tput lines)"
	fi
	COLUMNZ=$(tput cols)
}

trap RedrawTerm WINCH
trap ctrl_c INT
trap finish EXIT

Thousands () {
	FORMATTED=$(echo "${1}" | sed -r ':L;s=\b([0-9]+)([0-9]{3})\b=\1,\2=g;t L')
}

FileSize () {
	if [[ "${1}" == "-d" ]]; then
		DIR="${2}"
		FTP=""
	else
		FTP="${1}"
	fi
	if [[ -f "${FTP}" ]]; then
		TOTALSIZE=$(stat -c%s "${FTP}")
		Thousands "${TOTALSIZE}"
		KBS=$(echo "scale=2;${TOTALSIZE%/*}/1024"|bc)
		SIZE="${TOTALSIZE}"
		for XX in "${DISKSIZES[@]}"
		do
			SIZE=$(echo "scale=2;${SIZE%/*}/1024"|bc)
			# Dump the decimal just to see if we have hit the 1024 or less mark.
			KBS=$(echo "$SIZE" | cut -d . -f1)
			# Debugging:
			# echo "TESTINGSIZE: ${KBS} $XX"
			if [[ "${KBS}" -lt 1024 && "${KBS}" -gt 1 ]]; then
				TRUESIZE="${KBS}${XX}"
				#echo "${KBS} $XX"
			fi
		done
	else
		if [[ "${DIR}" ]]; then
			TOTALSIZE=$(du -s -B1 "${PWD}" | cut -d "/" -f1 | cut -f1)
			Thousands "${TOTALSIZE}"
			KBS=$(echo "scale=2;${TOTALSIZE%/*}/1024"|bc)
			SIZE="${TOTALSIZE}"
			for XX in "${DISKSIZES[@]}"
			do
				SIZE=$(echo "scale=2;${SIZE%/*}/1024"|bc)
				# Dump the decimal just to see if we have hit the 1024 or less mark.
				KBS=$(echo "${SIZE}" | cut -d . -f1)
				# Debugging:
				# echo "TESTINGSIZE: ${KBS} $XX"
				if [[ "${KBS}" -lt 1024 && "${KBS}" -gt 1 ]]; then
					TRUESIZE="${KBS}${XX}"
					#echo "${KBS} $XX"
				fi
			done
		else
			Error "${FTP} does not exist."
		fi
	fi
}

# Usage: Encapsulate
# Encapsulate "Repostorm 1.8.7 is entering extraction mode."
# Example: ▒ Repostorm 1.8.7 is entering extraction mode. ▒
Encapsulate () {
	# Verify a message has been sent to this otherwise do squat.
	# Example: Encapsulate ("Repostorm ${REPOVERSION} is entering extraction mode.")
	# ▒ Repostorm 1.7.7 is entering extraction mode.                       ▒

	STP="${1}"
	if [[ "${STP}" ]]; then
		STRLEN="${#STP}"
		((STRLEN=STRLEN + 3))
		((DISTANCE=COLUMNZ - STRLEN))
		GREPPED=$(echo "${STP}" | grep -E "")
		if [[ "${GREPPED}" ]]; then
			((STRLEN=STRLEN - 13))
		fi
		if ! [[ "${SUPPRESS}" ]]; then
			echo -en "${BRIGHT}${BLDWHT}▒ ${BRIGHT}${TXTGRN}${STP}"
		else
			echo "${STP}"
		fi
		if ! [[ "${SUPPRESS}" ]]; then
			RR=0; while [[ "${RR}" -lt "${DISTANCE}" ]]; do echo -n " "; ((RR=RR+1)); done; echo "${BRIGHT}${BLDWHT}▒";
		fi
	fi
	echo -en "${TXTRST}"
}

# Center data passed to on screen
# Center data passed to on screen
Center () {
	STP="${1}"
	ERRORRPT="${2}"
	if [[ "${STP}" ]]; then
		STRLEN="${#STP}"
		((CENTER=STRLEN / 2 ))
		#CENTER=CENTER-1
		((TCENTER=COLUMNZ / 2 ))
		#TCENTER=TCENTER-1
		((DISTANCE=TCENTER - CENTER))
		((DISTANCE=DISTANCE - 2))
		if ! [[ "${ERRORRPT}" ]]; then
			echo -en ""
		else
			echo -en "${TXTRED}"
		fi
		if ! [[ "${SUPPRESS}" ]]; then
			RR=0; while [[ "${RR}" -lt "${DISTANCE}" ]]; do echo -n "${BRIGHT}${BLDWHT}▒"; ((RR=RR+1)); done;
		fi
		if ! [[ "${ERRORRPT}" ]]; then
			echo -en ""
		else
			echo -en "${TXTRED}"
		fi
		echo -en " ${STP} "
		if ! [[ "${SUPPRESS}" ]]; then
			TT=0; while [ "${TT}" -lt "${DISTANCE}" ]; do echo -n "${BRIGHT}${BLDWHT}▒"; ((TT=TT+1)); done;
		fi
		((CALC=RR + TT + STRLEN + 2))
		if [[ "${CALC}" -lt "${COLUMNZ}" ]]; then
			if ! [[ "${SUPPRESS}" ]]; then
				while [[ "${CALC}" -lt "${COLUMNZ}" ]]; do echo -n "${BRIGHT}${BLDWHT}▒"; ((CALC=CALC+1)); done; echo;
			fi
		fi
	fi
	# echo "STRING LEN: ${STRLEN} CENTER: $CENTER TOTAL CNTER: $TCENTER RR:${RR} TT:${TT} COLUMNZ: ${COLUMNZ} CALC: ${CALC} DISTANCE: ${DISTANCE}"
	echo -en ""
}

# Draws a bar across the screen based on screen size detected (columnz)
FullBar () {
	if ! [[ "${SUPPRESS}" ]]; then
		RR=1; while [[ "${RR}" -le "${COLUMNZ}" ]]; do echo -n "${BRIGHT}${BLDWHT}▒"; ((RR=RR+1)); done; echo;
	fi
}

# for outputting to X-11 screen a notification of completion and playing sound.
# The sound file is from the "Optional" ultimate-edition-sound-theme
Notification () {
	# Is X11 running?
	X="${DISPLAY}"
	DISP=$(printf "[%s]" "${DISPLAY}" "${XAUTHORITY}" | grep ":0")

	#	X=$(xdpyINFO -display :0) >/dev/null
	if [[ "${DEBUG}" ]]; then
		echo "DEBUG: $X"
	fi
	# Does the user have the optional UE Sound scheme installed?
	if [[ -f "/usr/share/sounds/Ultimate Edition Sound Scheme/stereo/itisdone.wav" ]]; then
		WAVE="1"
	fi
	# Is the user in an X11 GUI environment and have notification OSD installed?
	if [[ "${DISP}" && "${NOTIFY}" ]]; then
		INSTALLED=$(type -p notify-send)
		if [[ "${INSTALLED}" ]]; then
			if ! [[ "${SUPPRESS}" ]]; then
				notify-send -u normal -a "${APPNAME}" "${1}" -i /usr/share/ultimate_edition/logo.png -t 5000
			fi
		fi
	fi
	# Does the user have pre-requisites? If so, break out the Cylon voice.
	if [[ "${SOUND}" && "${WAVE}" && "${DISP}" ]]; then
		INSTALLED=$(type -p canberra-gtk-play)
		if [[ "${INSTALLED}" ]]; then
			if ! [[ "${SUPPRESS}" ]]; then
				canberra-gtk-play --file "/usr/share/sounds/Ultimate Edition Sound Scheme/stereo/itisdone.wav" 2>/dev/null &
			fi
		fi
	fi
	# Display message in terminal unconditionally
	if ! [[ "${SUPPRESS}" ]]; then
		Encapsulate "${1}"
	fi
}

# Set a timer to display duration of download (s)
# Usage:  Timer [start|stop]
DownloadTimer () {
	TCMD="${1^^}"
	case "${TCMD}" in
		START) STARTS=$(date +%s)
		;;
		STOP) STOPS=$(date +%s)
			[[ ! "${STARTS}" ]] && Error "[Internal Error] Timer did not record a start time." && return
			(( DSECS=STOPS-STARTS))
			DLAPSE=$(date -u -d@"${DSECS}" +"%-Hh%-Mm%-Ss")
		;;
		*) Error "[Internal Error] Unknown arg ${TCMD}"
		;;
	esac

}

# Download various packages showing progression...
Download () {
	local URL="${1}"
	GREPIT=$(echo "${URL}" | grep -i "http")
	if [[ "${GREPIT}" ]]; then
		FILENAME=$(echo "${URL##*/}")
		if [[ -f "${FILENAME}" ]]; then
			Encapsulate "${FILENAME} exists, deleting for re-download."
			rm "${FILENAME}"
		fi
	else
		GREPIT=$(echo "${URL}" | grep -i "theme")
		if [[ "${GREPIT}" ]]; then
			URL="${THEMEFOLDER}/${1}"
		else
			URL="${ROOTFOLDER}/${1}"
		fi
	fi
	Encapsulate "Downloading: ${URL}"
	Encapsulate "Filename: ${FILENAME}"
	DownloadTimer "Start" "${FILENAME}"
    wget --progress=dot "${URL}" 2>&1 | grep --line-buffered "%" | sed -u -e "s,\.,,g" | awk '{printf("%4s", $2)}'

	echo -ne ""
	DownloadTimer "Stop" "${FILENAME}"
	FileSize "${FILENAME}"
	#echo $?
	Encapsulate "Download complete: ${FILENAME} ${FORMATTED} bytes (${TRUESIZE}). Download time: ${DLAPSE}"
}

# Dump data to the screen in pretty columns.
CColumnize () {
	declare -i USEDSPACE
	USEDSPACE=0
	ARRAY_COUNTER=0
	TLEN=0
	# Columnize is an internally called function exclusively.
	# EXAMPLE
	# -t to shove through the column titles we will count the number of switches and
	# calculate spacing eventually.
	if [[ "${1}" == "-t" ]]; then
		USEDSPACE=151
	else
		#echo -e "${bldgrn}Number of switches PASSed: $#"
		for ARG in "$@"
		do
			ARRAY_COUNTER=$((ARRAY_COUNTER + 1))
			if [[ "${ARRAY_COUNTER}" -gt 4 ]]; then
				ARGUMENTS[$ARRAY_COUNTER]="${ARG}"
				TLEN="${#ARGUMENTS[$ARRAY_COUNTER]}"
				USEDSPACE=149
				USEDSPACE=$((USEDSPACE + "${TLEN}"))
				# echo "Switch $ARRAY_COUNTER: $ARG (${TLEN}) | USEDSPACE:${USEDSPACE}"
				#echo "Length of ${ARGUMENTS[$ARRAY_COUNTER]} is $TLEN"
			fi
			#echo "The widest PASSed varible is $WIDEST"
		done
	fi
	#echo "#: $# VARS: $*"
	#LONGESTLENGTH="${#2}"
	#echo "Length of ${2} is $LONGESTLENGTH"
	#echo ${COLUMNZ}
	#echo "${MAINS}"
	if [[ "${1}" = '-t' ]]; then
		#"#" "DEV" "VENDOR" "LABEL" "TYPE" "SIZE"
		printf "%-0s %-36s %-14s %-14s %-14s %-1s" "▒" "${2}" "${3}" "${4}" "${5}" "${6}"
	else
		#MAINS=$(expr $MAINS / 2)
		printf "%-0s %-36s %-14s %-14s %-14s %-${MAINS}s %-1s" "▒" "${1}" "${2}" "${3}" "${4}" "${5}"
	fi
	echo -e "\033[${COLUMNZ}G▒"
}

# Dump data to the screen in pretty columns.
Columnize () {
	declare -i USEDSPACE
	USEDSPACE=0
	ARRAY_COUNTER=0
	TLEN=0
	# Columnize is an internally called function exclusively.
	# EXAMPLE
	# -t to shove through the column titles we will count the number of switches and
	# calculate spacing eventually.
	if [[ "${1}" == "-t" ]]; then
		USEDSPACE=151
	else
		#echo -e "${bldgrn}Number of switches PASSed: $#"
		for ARG in "$@"
		do
			ARRAY_COUNTER=$((ARRAY_COUNTER + 1))
			if [[ "$ARRAY_COUNTER" -gt 4 ]]; then
				ARGUMENTS[$ARRAY_COUNTER]="$ARG"
				TLEN="${#ARGUMENTS[$ARRAY_COUNTER]}"
				USEDSPACE=149
				USEDSPACE=$((USEDSPACE + "${TLEN}"))
				# echo "Switch $ARRAY_COUNTER: $ARG (${TLEN}) | USEDSPACE:${USEDSPACE}"
				#echo "Length of ${ARGUMENTS[$ARRAY_COUNTER]} is $TLEN"
			fi
			#echo "The widest PASSed varible is $WIDEST"
		done
	fi
	#echo "#: $# VARS: $*"
	#LONGESTLENGTH="${#2}"
	#echo "Length of ${2} is $LONGESTLENGTH"
	#echo ${COLUMNZ}
	#echo "${MAINS}"
	if [[ "${1}" = '-t' ]]; then
		#"#" "DEV" "VENDOR" "LABEL" "TYPE" "SIZE"
		printf "%-0s %-60s %-14s %-56s %-13s %-1s" "▒" "${2}" "${3}" "${4}" "${5}" "${6}"
	else
		#MAINS=$(expr $MAINS / 2)
		printf "%-0s %-60s %-14s %-56s %-13s %-${MAINS}s %-1s" "▒" "${1}" "${2}" "${3}" "${4}" "${5}"
	fi
	echo -e "\033[${COLUMNZ}G▒"
}

# Dump data to the screen in pretty columns.
EColumnize () {
	declare -i USEDSPACE
	USEDSPACE=0
	ARRAY_COUNTER=0
	TLEN=0
	# Columnize is an internally called function exclusively.
	# EXAMPLE
	# -t to shove through the column titles we will count the number of switches and
	# calculate spacing eventually.
	if [[ "${1}" == "-t" ]]; then
		USEDSPACE=151
	else
		#echo -e "${bldgrn}Number of switches PASSed: $#"
		for ARG in "$@"
		do
			ARRAY_COUNTER=$((ARRAY_COUNTER + 1))
			if [[ "$ARRAY_COUNTER" -gt 4 ]]; then
				ARGUMENTS[$ARRAY_COUNTER]="$ARG"
				TLEN="${#ARGUMENTS[$ARRAY_COUNTER]}"
				USEDSPACE=149
				USEDSPACE=$((USEDSPACE + "${TLEN}"))
				# echo "Switch $ARRAY_COUNTER: $ARG (${TLEN}) | USEDSPACE:${USEDSPACE}"
				#echo "Length of ${ARGUMENTS[$ARRAY_COUNTER]} is $TLEN"
			fi
			#echo "The widest PASSed varible is $WIDEST"
		done
	fi
	#echo "#: $# VARS: $*"
	#LONGESTLENGTH="${#2}"
	#echo "Length of ${2} is $LONGESTLENGTH"
	#echo ${COLUMNZ}
	#echo "${MAINS}"
	LONGESTFILENAME=$(find . | awk 'function base(f){sub(".*/", "", f); return f;} {print length(base($0))}'| sort -nr | head -1)
	(( LONGESTFILENAME = LONGESTFILENAME + 2)) # Allow for space before and after and the /
	if [[ "${1}" == "-t" ]]; then
		#"#" "DEV" "VENDOR" "LABEL" "TYPE" "SIZE"
		printf "%-0s %-${LONGESTFILENAME}s %-12s %-12s %-12s %-1s" "▒" "${BLDBLU}${2}" "${TXTRED}${3}" "${YELLOW}${4}" "${BLDWHT}${5}" "${6}"
	else
		#MAINS=$(expr $MAINS / 2)
		printf "%-0s %-${LONGESTFILENAME}s %-13s %-15s %-15s %-${MAINS}s %-1s" "▒" "${BLDBLU}${1}" "${TXTRED}${2}" "${YELLOW}${3}" "${BLDWHT}${4}" "${5}"
	fi
	echo -e "\033[${COLUMNZ}G▒"
}

# Dump data to the screen in pretty columns for folders.
FColumnize () {
	declare -i USEDSPACE
	USEDSPACE=0
	ARRAY_COUNTER=0
	TLEN=0
	# Columnize is an internally called function exclusively.
	# EXAMPLE
	# -t to shove through the column titles we will count the number of switches and
	# calculate spacing eventually.
	if [[ "${1}" == "-t" ]]; then
		USEDSPACE=151
	else
		#echo -e "${bldgrn}Number of switches PASSed: $#"
		for ARG in "$@"
		do
			ARRAY_COUNTER=$((ARRAY_COUNTER + 1))
			if [[ "$ARRAY_COUNTER" -gt 4 ]]; then
				ARGUMENTS[$ARRAY_COUNTER]="$ARG"
				TLEN="${#ARGUMENTS[$ARRAY_COUNTER]}"
				USEDSPACE=149
				USEDSPACE=$((USEDSPACE + "${TLEN}"))
				# echo "Switch $ARRAY_COUNTER: $ARG (${TLEN}) | USEDSPACE:${USEDSPACE}"
				#echo "Length of ${ARGUMENTS[$ARRAY_COUNTER]} is $TLEN"
			fi
			#echo "The widest PASSed varible is $WIDEST"
		done
	fi
	#echo "#: $# VARS: $*"
	#LONGESTLENGTH="${#2}"
	#echo "Length of ${2} is $LONGESTLENGTH"
	#echo ${COLUMNZ}
	#echo "${MAINS}"
	LONGESTFILENAME=$(find . -mindepth 1 -maxdepth 1 -type d | awk 'function base(f){sub(".*/", "", f); return f;} {print length(base($0))}'| sort -nr | head -1)
	(( LONGESTFILENAME = LONGESTFILENAME + 10)) # Allow for space before and after.
	if [[ "${1}" == "-t" ]]; then
		#"#" "DEV" "VENDOR" "LABEL" "TYPE" "SIZE"
		printf "%-0s %-${LONGESTFILENAME}s %-13s %-15s %-15s %-1s" "▒" "${BLDBLU}${2}" "${TXTRED}${3}" "${YELLOW}${4}" "${BLDWHT}${5}" "${6}"
	else
		#MAINS=$(expr $MAINS / 2)
		printf "%-0s %-${LONGESTFILENAME}s %-13s %-15s %-15s %-${MAINS}s %-1s" "▒" "${BLDBLU}${1}" "${TXTRED}${2}" "${YELLOW}${3}" "${BLDWHT}${4}" "${5}"
	fi
	echo -e "\033[${COLUMNZ}G▒"
}

TColumnize() {
	# Columnize is an internally called function exclusively.
	# EXAMPLE
	# -t to shove through the column titles we will count the number of switches and
	# calculate spacing eventually.
	if [[ "${1}" == "-t" ]]; then
		#echo -e "${bldgrn}Number of switches passed: $#"
		for ARG in "$@"
		do
			array_counter=$((array_counter + 1))
			if [[ "$array_counter" -gt 2 ]]; then
				#echo "Switch $array_counter: $ARG"
				ARGUMENTS[$array_counter]="$ARG"
				tLen="${#ARGUMENTS[$array_counter]}"
				if [[ $tLen -ge $WIDEST ]]; then
					WIDEST="$tLen"
				fi
				#echo "Length of ${ARGUMENTS[$array_counter]} is $tLen"
			fi
			#echo "The widest passed varible is $WIDEST"
		done
	else
		#echo -e "${bldgrn}Number of switches passed: $#"
		for ARG in "$@"
		do
			array_counter=$((array_counter + 1))
			if [[ "$array_counter" -gt 1 ]]; then
				#echo "Switch $array_counter: $ARG"
				ARGUMENTS[$array_counter]="$ARG"
				tLen="${#ARGUMENTS[$array_counter]}"
				if [[ "$tLen" -ge "$WIDEST" ]]; then
					WIDEST="$tLen"
				fi
				#echo "Length of ${ARGUMENTS[$array_counter]} is $tLen"
			fi
			#echo "The widest passed varible is $WIDEST"
		done
	fi
	#echo "#: $# VARS: $*"
	#LONGESTLENGTH="${#2}"
	#echo "Length of ${2} is $LONGESTLENGTH"
	#echo ${COLUMNZ}
	MAINS=$(echo "scale=2; ${COLUMNZ}-30" | bc)
	MAINS=${MAINS%.*}
	#echo $MAINS
	MAINS=$((MAINS - 2))
	MAINS=$((MAINS / 4))
	#echo $MAINS
	if [[ "${1}" = '-t' ]]; then
		#"#" "DEV" "VENDOR" "LABEL" "TYPE" "SIZE"
		printf "%-0s %-26s %-8s %-16s %-5s %-3s %-13s %-16s %-16s %-1s\n" "▒" "${2}" "${3}" "${4}" "${5}" "${6}" "${7}" "${8}" "${9}"
	else
		#MAINS=$(expr $MAINS / 2)
		printf "%-0s %-26s %-8s %-16s %-5s %-3s %-13s %-16s %-16s %-1s\n" "▒" "${1}" "${2}" "${3}" "${4}" "${5}" "${6}" "${7}" "${8}" "${9}"
	fi
}

# Dump data to the screen in pretty columns.
CColumnize () {
	declare -i USEDSPACE
	USEDSPACE=0
	ARRAY_COUNTER=0
	TLEN=0
	# Columnize is an internally called function exclusively.
	# EXAMPLE
	# -t to shove through the column titles we will count the number of switches and
	# calculate spacing eventually.
	if [[ "${1}" == "-t" ]]; then
		USEDSPACE=151
	else
		#echo -e "${bldgrn}Number of switches PASSed: $#"
		for ARG in "$@"
		do
			ARRAY_COUNTER=$((ARRAY_COUNTER + 1))
			if [[ "$ARRAY_COUNTER" -gt 4 ]]; then
				ARGUMENTS[$ARRAY_COUNTER]="$ARG"
				TLEN="${#ARGUMENTS[$ARRAY_COUNTER]}"
				USEDSPACE=149
				USEDSPACE=$((USEDSPACE + "${TLEN}"))
				# echo "Switch $ARRAY_COUNTER: $ARG (${TLEN}) | USEDSPACE:${USEDSPACE}"
				#echo "Length of ${ARGUMENTS[$ARRAY_COUNTER]} is $TLEN"
			fi
			#echo "The widest PASSed varible is $WIDEST"
		done
	fi
	#echo "#: $# VARS: $*"
	#LONGESTLENGTH="${#2}"
	#echo "Length of ${2} is $LONGESTLENGTH"
	#echo ${COLUMNZ}
	#echo "${MAINS}"
	LONGESTFILENAME=$(find . | awk 'function base(f){sub(".*/", "", f); return f;} {print length(base($0))}'| sort -nr | head -1)
	(( LONGESTFILENAME = LONGESTFILENAME + 5)) # Allow for space before and after.
	if [[ "${1}" == "-t" ]]; then
		#"#" "DEV" "VENDOR" "LABEL" "TYPE" "SIZE"
		printf "%-0s %-${LONGESTFILENAME}s %-12s %-12s %-12s %-1s" "▒" "${2}" "${3}" "${4}" "${5}" "${6}"
	else
		#MAINS=$(expr $MAINS / 2)
		printf "%-0s %-${LONGESTFILENAME}s %-13s %-15s %-15s %-${MAINS}s %-1s" "▒" "${1}" "${2}" "${3}" "${4}" "${5}"
	fi
	echo -e "\033[${COLUMNZ}G▒"
}

Error () {
	Center "${1}" "--ERROR"
}

# Usage: Eye Candy "Message"
# Example: Eye Candy "Repostorm ${REPOVERSION} is entering extraction mode."
# ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
# ▒ Repostorm 1.7.7 is entering extraction mode. ▒
# ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
EyeCandy () {
	# Verify a message has been sent to this otherwise do squat.

	STP="${1}"
	if [[ "${STP}" ]]; then
		STRLEN="${#STP}"
		((STRLEN=STRLEN + 3))
		GREPPED=$(echo "${STP}" | grep -E "")
		if [[ "${GREPPED}" ]]; then
			((STRLEN=STRLEN - 13))
		fi
		if ! [[ "${SUPPRESS}" ]]; then
			RR=0; while [[ "${RR}" -le "${STRLEN}" ]]; do echo -n "▒"; ((RR=RR+1)); done; echo;
		fi
		echo -e "${BLDWHT}▒${TXTGRN} ${STP} ${BLDWHT}▒"
		if ! [[ "${SUPPRESS}" ]]; then
			RR=0; while [[ "${RR}" -le "${STRLEN}" ]]; do echo -n "▒"; ((RR=RR+1)); done; echo;
		fi
	fi
	echo -en "${TXTRST}"
}

# Set a timer to display duration ##
# Usage:  Timer <[start|stop]> <OBJECT>
Timer () {
	# Debugging switches... Uncomment to see output: 03/30/2016 added as an
	# Optional switch - useful for me and the end user.
	# Internal function Sample: Timer "Start" "Downloading Files"
	# Download "Blah, blah, ..."
	# Timer "Stop" "Downloading Files"
	# Results: Timer Complete Downloading Files: 0h0m40s
	# With function FileSize:
	# Downloaded: 178 files a total of 13,741,490,176 bytes (12GB) in 0h0m40s
	if [[ "${DEBUG}" ]]; then
		shopt -s expand_aliases
		# shellcheck disable=SC2128
		Center "DEBUG INFORMATION: ${FUNCNAME}"
		# a bug has been filed against shellcheck: https://github.com/koalaman/shellcheck/issues/634
		echo -en "Caller: "
		caller
	fi
	if [[ "${2}" ]]; then
		OBJECT[${TINDEX}]="${2}"
	fi
	TCMD="${1^^}"

	case "${TCMD}" in
		START) STARTSECS[${TINDEX}]=$(date +%s)
				if [[ "${OBJECT[${TINDEX}]}" ]]; then
					if [[ "${2}" != "${APPNAME^}" ]]; then
						Encapsulate "Timer Started: ${OBJECT[${TINDEX}]}"
					fi
				fi
				(( TINDEX + 1 ))
		;;
		STOP) 	CINDEX=0
				for EACH in "${OBJECT[@]}"
				do
					if [[ "${EACH}" == "${2}" ]]; then
						FINDEX="${CINDEX}"
					fi
					(( CINDEX + 1 ))
				done
				STOPSECS[${FINDEX}]=$(date +%s)
				[[ ! "${STARTSECS[${FINDEX}]}" ]] && Error "[Internal Error] Timer did not record a start time." && return
				(( DIFFSECS=STOPSECS[${FINDEX}]-STARTSECS[${FINDEX}] ))
				TIMELAPSE=$(date -u -d@"${DIFFSECS}" +"%-Hh%-Mm%-Ss")
				if [[ "${OBJECT[${FINDEX}]}" ]]; then
					Encapsulate "Timer Complete ${OBJECT[$FINDEX]}: ${TIMELAPSE}"
				fi

		;;
		*) Error "[Internal Error] ${FUNCNAME}: Unknown arg ${TCMD}"
	esac
	TTIMEM="${TIMELAPSE}"
}

FormatNUM () {
    INPUTNUM="${1}"
    if [[ "${INPUTNUM}" ]]; then
        OUTPUTNUM=$(echo "${INPUTNUM}" | sed ':a;s/\B[0-9]\{3\}\>/,&/;ta')
    fi
}

# Dump version information and exit function
VersionDump () {
	# Debugging switches... Uncomment to see output: 03/30/2016 added as an
	# Optional switch - useful for me and the end user.
	AMOUNT=0
	if [[ "${DEBUG}" ]]; then
		Center "DEBUG INFORMATION: ${FUNCNAME[1]}"
		for EACH in "$@"
		do
			((AMOUNT ++))
			echo "$AMOUNT:${EACH} "
		done
		echo -e -n "Caller [LINE] / APP: "
		caller
		FullBar
		echo -e -n "${TXTRST}"
	fi
	if ! [[ "${SUPPRESS}" ]]; then
		Center "${APPNAME} (${PROGNAME}) ${VERSION}, ${BUILDDATE}"
		Encapsulate "GNU ${PROGNAME} home page: <https://${WEBSITE}/>."
		Encapsulate "E-mail bug reports to: ${EMAIL}."
		Encapsulate "Be sure to include the word ${PROGNAME} somewhere in the Subject: field."
		FullBar
	fi
}

CheckRoot () {
	if [[ "${EUID}" -ne 0 ]]; then
		Error "Please run as root or sudo privilages."
		exit 1;
	fi
}

Spinner () {
	local DATA="${1}"
	local PID="$!"
	local DELAY=0.1
	local SPINSTR='|/-\'
	declare -i CHARS
	while kill -0 "${PID}" 2> /dev/null; do
		local TEMP="${SPINSTR#?}"
		printf "${BRIGHT}${BLDWHT}▒ ${BRIGHT}${TXTGRN}[%c] ${DATA}" "${SPINSTR}"
		local SPINSTR="${TEMP}${SPINSTR%"${TEMP}"}"
		sleep "${DELAY}"
		local RESET="\b\b\b\b\b\b\b\b\b"
		local CHARS=$(echo "${DATA}" | wc -c)
		for (( I=0; I<${#DATA}; I++ ))
		do
			RESET+="\b"
		done
		printf "${RESET}"
	done
	printf "    \b\b\b\b"
}

# Text formatting in a pretty style based on the size of the users screen real estate.
FormatText () {
	shopt -u nullglob
	declare -a STP=();
	TTF="${1}"
	DTP=$(printf %s\\n "${TTF}")
	AVAILWIDTH=$(("${COLUMNZ}" -4))
	# echo "WIDTH: ${AVAILWIDTH}"
	OIFS=$IFS
	IFS=$'\n'
	STP=$(echo "${DTP}" | fmt -s -u -w "${AVAILWIDTH}")
	STP=(${STP})
	#IFS=$'\n'
	#printf '%s\n' "${text[*]}" | fmt -w 45
	#STP=$(echo "${TTF}" | fmt -u -w "${AVAILWIDTH}")
	for EACH in "${STP[@]}"
	do
		Encapsulate "${EACH}"
	done
	IFS=$OIFS
}

# Only to be used when something you are writing takes a very long time to complete
# Data is the title of what is being processed. Percent is the percentage complete.
# Example: ProgressBar "50.1" "Processing ISO 366 of 730"
# the software calculates the length of the strings being processed & adjusts.
# Acuracy is not necessary here. We are bot going to wastefully call on tools for percision.
ProgressBar ()  {
	local DATA
	local PERCENT
	DATA="${2}"
	PERCENT="${1%.*}"
	DLEN="${#DATA}"
	c=$(( "${COLUMNZ}"-"${DLEN}"-${#PERCENT}-7 ))
	j=$((${PERCENT}*c/100))
	tput sc
	printf "▒ ${DATA}: ${PERCENT}%% $(for((k=0;k<j;k++));do printf "▒";done;)"
	tput cuf $((c-j))
	printf "▒"
	tput rc;
}

BigBarFiles ()  {
	local DATA
	local PERCENT
	LONGESTFILENAME=$(find . -maxdepth 1 -type f -iname "*.deb" | awk 'function base(f){sub(".*/", "", f); return f;} {print length(base($0))}'| sort -nr | head -1)
	(( LONGESTFILENAME = LONGESTFILENAME + 2 + ${#CDATA} )) # Allow for space before and after.
	DATA="${2}"
	PERCENT="${1%.*}"
	CDATA="${3}"
	M="${4}"
	LOV="${5}"
	DLEN="${#DATA}"
	c=$(( "${COLUMNZ}" - "${LONGESTFILENAME}" - 3 - ${#CDATA} - 6 ))
	j=$((${PERCENT}*c/100))
	tput sc
	printf "%-0s %-${LONGESTFILENAME}s %-${#CDATA}s %-3s %-${J}s %-1s" "▒" "${DATA}" "${M}"  "${PERCENT}% $(for((k=0;k<j;k++));do printf "▒";done;)"
	# ;tput cuu1;tput el;
	tput cuf $((${COLUMNZ}))
	printf "▒"
	tput rc;
}

BigBarFolders ()  {
	shopt -s dotglob
    shopt -s nullglob
	local DATA
	local PERCENT
	DATA="${2}"
	LFN="${1}"
	PERCENT="${5%.*}"
	CDATA="${3}"
	PROG="${4}"
	DLEN="${#DATA}"
	c=$(( "${COLUMNZ}" - "${LFN}" - 3 - ${CDATA} - 6 ))
	j=$((${PERCENT}*c/100))
	tput sc
	printf "%-0s %-${LFN}s %-${CDATA}s %-3s %-${J}s %-1s" "▒" "${DATA}" "${PROG}" "${PERCENT}% $(for((k=0;k<j;k++));do printf "▒";done;)"
	# ;tput cuu1;tput el;
	tput cuf $((${COLUMNZ}))
	printf "▒"
	tput rc;
}

PromptYN () {
	YN=""
	while true; do
		echo -en "▒ ${1}"
		read YN
		echo -en "\033[1A\033[2K"
		case "${YN}" in
			[Nn]* ) return 1;;
			[Yy]* ) return 0;
					break;;
				* ) Encapsulate "Please answer y or n.";;
		esac
	done
}

# TMOSB Specific
# Try to think of the below as a basic database where the values coincide
# Example when it detects 14.10 the arrays will be cycled through looking for
# the value of 14.10 as the UEARRAY would be value[16] the value of
# [16] of DISTARRAY would be Trusty Tahr
#DISTSSUPPORTED=48
declare -i DISTSSUPPORTED;
declare -a ISLTS=( "4.2" "4.3" "5.0" "5.1" "5.8" "5.9" "6.6" "6.7" "7.4" "7.5" "12.04" "14.04" "16.04" "18.04" "20.04" "22.04" );
declare -a OSARRAY=( 'quantal' 'quantal' 'raring' 'raring' 'saucy' 'saucy' 'trusty' 'trusty' 'utopic' 'utopic' 'vivid' 'vivid' 'wily' 'wily' 'xenial' 'xenial' 'yakkety' 'yakkety' 'zesty' 'zesty' 'artful' 'artful' 'bionic' 'bionic' 'cosmic' 'cosmic' 'disco' 'disco' 'eoan' 'eoan' 'focal' 'focal' 'groovy' 'groovy' 'hirsute' 'hirsute' 'impish' 'impish' 'jammy' 'jammy' 'quantal' 'quantal' 'raring' 'raring' 'saucy' 'saucy' 'trusty' 'trusty' 'utopic' 'utopic' 'vivid' 'vivid' 'wily' 'wily' 'xenial' 'xenial' 'yakkety' 'yakkety' 'zesty' 'zesty' 'artful' 'artful' 'bionic' 'bionic' 'cosmic' 'cosmic' 'disco' 'disco' 'eoan' 'eoan' 'focal' 'focal' 'groovy' 'groovy' 'hirsute' 'hirsute' 'impish' 'impish' 'jammy' );
declare -a UEARRAY=( "3.6" "3.7" "3.8" "3.9" "4.0" "4.1" "4.2" "4.3" "4.4" "4.5" "4.6" "4.7" "4.8" "4.9" "5.0" "5.1" "5.2" "5.3" "5.4" "5.5" "5.6" "5.7" "5.8" "5.9" "6.0" "6.1" "6.2" "6.3" "6.4" "6.5" "6.6" "6.7" "6.8" "6.9" "7.0" "7.1" "7.2" "7.3" "7.4" "7.5" '12.10' '13.04' '13.10' '14.04' '14.10' '15.04' '15.10' '16.04' '16.10' '17.04' '17.10' '18.04' '18.10' '19.04' '19.10' '20.04' '20.10' '21.04' '22.04');
DISTSSUPPORTED="${#UEARRAY[@]}"
NEWESTUE="${UEARRAY[${DISTSSUPPORTED}/3*2-1]}"
#declare -a DEBIAN=("7.6" "7.7" "7.8" "7.9" "7.10" "7.11");
declare -a DISTARRAY=( "Quantal Quetzal" "Quantal Quetzal" "Raring Ringtail" "Raring Ringtail" "Saucy Salamander" "Saucy Salamander" "Trusty Tahr" "Trusty Tahr" "Utopic Unicorn" "Utopic Unicorn" "Vivid Vervet" "Vivid Vervet" "Wily Werewolf" "Wily Werewolf" "Xenial Xerus" "Xenial Xerus" "Yakkety Yak" "Yakkety Yak" "Zesty Zapus" "Zesty Zapus" "Artful Aardvark" "Artful Aardvark" "Bionic Beaver" "Bionic Beaver" "Cosmic Cuttlefish" "Cosmic Cuttlefish" "Disco Dingo" "Disco Dingo" "Eoan Ermine" "Eoan Ermine" "Focal Fossa" "Focal Fossa" "Groovy Gorilla" "Groovy Gorilla" "Hirsute Hippo" "Hirsute Hippo" "Impish Indri" "Impish Indri" "Jammy Jellyfish" "Jammy Jellyfish" "Quantal Quetzal" "Raring Ringtail" "Saucy Salamander" "Trusty Tahr" "Utopic Unicorn" "Vivid Vervet" "Wily Werewolf" "Xenial Xerus" "Yakkety Yak" "Zesty Zapus" "Artful Aardvark" "Bionic Beaver" "Cosmic Cuttlefish" "Disco Dingo" "Eoan Ermine" "Focal Fossa" "Groovy Gorilla" "Hirsute Hippo" "Impish Indri" "Jammy Jellyfish" );
declare -a UBUNTU=( '12.10' '13.04' '13.10' '14.04' '14.10' '15.04' '15.10' '16.04' '16.10' '17.04' '17.10' '18.04' '18.10' '19.04' '19.10' '20.04' '20.10' '21.04' '22.04' );
declare -a DEBIAN=( "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15" "16" );
declare -a DEBIANARRAY=( "Buzz" "Rex" "Bo" "Hamm" "Slink" "Potato" "Woody" "Sarge" "Etch" "Lenny" "Squeeze" "Wheezy" "Jessie" "Stretch" "Buster" "Bullseye" );
#UETYPE=5
#declare -a UETYPES=("lite" "gamers" "server" "minimal-server");
#declare -a DEBS=("lite" "gamers" "server" "minimal-server" "standard" "full");
#declare -a DEBIAN=("7.6" "7.7");
#UETYPE=5
declare -a UETYPES=( "lite" "gamers" "server" "minimal-server" "developer" );
declare -a DEBS=( "lite" "gamers" "server" "minimal-server" "standard" "full" "developer" );
#declare -a DEBIAN=("7.6" "7.7" "7.8" "7.9" "7.10" "7.11");
declare -a UEARCH=( "x64" "x86" "amd64" "i386" "armel" "armhf" "powerpc" "powerpc-smp" "ppc64el" );
declare -a OLDRELEASES=( "2.6" "2.7" "3.4" "3.5" );
declare -a DISTBASE=( "Ultimate Edition" "Ubuntu" "Debian" );
declare -a CYCLE=( "x86" "x64" "armel" "armhf" "powerpc" "powerpc-smp" "ppc64el" );
declare -a EXTRADE=( "xfce" "mate" "kde" "trinity" "lxde" "awesome" "gnome" "lxqt" "unity" "cinnamon" "budgie" "enlightenment" "pantheon" "deepin" );
#declare -i CVER;
#declare -i CSIZE;
declare -a APPLICATIONS=( 'tmosb' 'uecorebuilder' 'uesplash-builder' 'tmgrub' 'internal' );
declare -a APPSRC=( '/bin' '/bin' '/bin' '/usr/share/ultimate_edition' '/usr/share/ultimate_edition' );
declare -a ARGUMENTS=();
#declare -a ARGLENGTH=();
declare -a LOGFILEZ=( "bootstrap.log" "history.log" "dpkg.log" );
declare -a MOUNTPOINTS=( "proc/" "sys/" "dev/");
declare -a UEONLY=( "3.6" "3.7" "3.8" "3.9" "4.0" "4.1" "4.2" "4.3" "4.4" "4.5" "4.6" "4.7" "4.8" "4.9" "5.0" "5.1" "5.2" "5.3" "5.4" "5.5" "5.6" "5.7" "5.8" "5.9" "6.0" "6.1" "6.2" "6.3" "6.4" "6.5" "6.6" "6.7" "6.8" "6.9" "7.0" "7.1" "7.2" "7.3" "7.4" "7.5" );
declare -a UEDISTARRAY=( "Quantal Quetzal" "Quantal Quetzal" "Raring Ringtail" "Raring Ringtail" "Saucy Salamander" "Saucy Salamander" "Trusty Tahr" "Trusty Tahr" "Utopic Unicorn" "Utopic Unicorn" "Vivid Vervet" "Vivid Vervet" "Wily Werewolf" "Wily Werewolf" "Xenial Xerus" "Xenial Xerus" "Yakkety Yak" "Yakkety Yak" "Zesty Zapus" "Zesty Zapus" "Artful Aardvark" "Artful Aardvark" "Bionic Beaver" "Bionic Beaver" "Cosmic Cuttlefish" "Cosmic Cuttlefish" "Disco Dingo" "Disco Dingo" "Eoan Ermine" "Eoan Ermine" "Focal Fossa" "Focal Fossa" "Groovy Gorilla" "Hirsute Hippo" "Impish Indri" "Jammy Jellyfish" );
declare -a EXTRADE=( "XFCE" "MATE" "KDE" "LXDE" "AWESOME" "GNOME" "LXQT" "UNITY" "CINNAMON" "BUDGIE" "ENLIGHTENMENT" "DEEPIN" );
#declare -a DELOCATIONS=(".xfce" ".config/mate" ".kde" ".lxde" ".awesome" ".gnome" ".LX" ".unity" ".cinnamon");
declare -a SERVEROPTIONS=( "sql" "ftp" "wordpress" "apache" "php" "awstats" "monitor" );
declare -a SERVERPACKAGES=( "mysql-server" "vsftpd" "wordpress" "lamp-server^" "awstats, libgeo-ipfree-perl, libnet-ip-perl" "vnstat, htop, bmon, nload, iftop, iptraf, nethogs, slurm, tcptrack, cbm, speedometer, ssh" );
# PRE-DETERMINE user selection
GAMERS=$(echo "$*" | grep -i "gamers")
SERVER=$(echo "$*" | grep -i "server")
MSERVER=$(echo "$*" | grep -i "minimal-server")
LITE=$(echo "$*" | grep -i "lite")
DEVELOPER=$(echo "$*" | grep -i "developer")
if [[ "${GAMERS}" ]]; then
	DEBTYPE="gamers"
	DTYPE="gamers"
fi
if [[ "${SERVER}" ]]; then
	DEBTYPE="server"
	DTYPE="server"
fi
if [[ "${MSERVER}" ]]; then
	DEBTYPE="minimal-server"
	DTYPE="minimal-server"
fi
if [[ "${LITE}" ]]; then
	DEBTYPE="lite"
	DTYPE="lite"
fi
if [[ "${DEVELOPER}" ]]; then
	DEBTYPE="developer"
	DTYPE="developer"
fi
if [[ "${MSERVER}" ]]; then
	SERVER=""
	DTYPE="Minimal-Server"
	DE="NONE"
fi
