#!/bin/bash

# APSK Bash Debugging Library
#
# by Apollia - http://apollia.com/
#
#
# 2020-09-11 01:32:46.  A library of Bash functions useful for debugging,
# such as backtrace, forthtrace, announcing entrances to and exits from
# a function, and printing strings or arrays with the source location
# automatically displayed above what you printed.
#
# With most of the functions that are intended for developer use, you can
# control whether they get run or not by providing a tag argument, and/or
# by changing the config vars and arrays listed below.
#
# Also, you can make it so debug functions only get run if they're called
# from a particular function or set of functions that you're curious about.
#
# However, tag includes or excludes take precedence over function includes
# or excludes.
#
#
# This app's Git repo:
#
#	https://apollia.org/gitlist/APSK-Bash-Debugging-Tools.git
#
#
# 2020-12-08 01:01:57.
#
# List of all functions especially intended for developer use:
#
#		decho
#
#		ardecho
#		hashdecho
#
#		echoar
#		echohash
#
#		backtrace (or bt)
#		forthtrace (or ft)
#
#		Decho____Now_In_This_Function
#		Decho____Back_In_This_Function
#		Decho____Now_Exiting_This_Function
#
#		APSK_Debug____Print_All_Unique_Tags_Used
#
#		techo (or tagged_echo)
#
#		teval (or tagged_eval)
#		dexit
#
#
# Doesn't have tag feature or source location header:
#
#		APSK_Debug____PrintArr
#		APSK_Debug____PrintHash
#
#
# See the rest of this source code for more details.



#-------------------------------------------------------------------------------------------------------------------
#
# 2020-09-08 02:31:24.  Copy-and-pasteable, developer-settable config vars
# and arrays.
#
# But you shouldn't edit them here - you should copy and paste
# the below into your own program and edit them there.
#
#-------------------------------------------------------------------------------------
#
# *(*)*
#
# 03:45:38 09/11/2020.  APSK Bash Debugging Library config:
#
#

APSK_DEBUG_MODE=true

APSK_Debug____should_print_Now_in_Function_headers=true
APSK_Debug____should_print_Back_in_Function_headers=true
APSK_Debug____should_print_Now_Exiting_This_Function_footers=true


APSK_Debug____should_allow_decho=true
	# 2020-09-08 17:20:24.  Doesn't affect printing of function headers
	# or footers.

APSK_Debug____should_allow_dexit=true


APSK_Debug____should_allow_ardecho=true
APSK_Debug____should_allow_echoar=true


APSK_Debug____should_allow_hashdecho=true
APSK_Debug____should_allow_echohash=true


APSK_Debug____should_allow_backtrace=true
	# 2020-09-09 23:19:15.  Only affects bt() and backtrace().

APSK_Debug____should_allow_forthtrace=true
	# 2020-09-10 08:39:29.  Only affects ft() and forthtrace().
	

APSK_Debug____should_allow_tagged_echo=true
	# 2020-11-01 10:32:29. Only affects techo() and tagged_echo().
	
APSK_Debug____should_allow_tagged_eval=true
	# 2020-10-17 00:20:16.  Only affects teval() and tagged_eval().


APSK_Debug____should_allow_printing_of_unique_tags=true
	# 2020-09-08 22:16:25.  Only affects APSK_Debug____Print_All_Unique_Tags_Used().


# 2020-09-06 23:03:50.  If anything is in these Include arrays,
#debug mode gets aborted for anything not in these arrays:
	
APSK_Debug____Functions_to_Include=(
	
	)

APSK_Debug____Tags_to_Include=(
	)


# 2020-09-06 23:08:44.  If these Exclude arrays are used instead,
# debug mode is allowed to continue for everything except the
# excluded items:
	
APSK_Debug____Tags_to_Exclude=(
	
	)

APSK_Debug____Functions_to_Exclude=(
	
	)



# 2020-09-07 23:21:55.  Used to determine whether
# Decho____Now_In_This_Function should be allowed to run:		

APSK_Debug____Function_Headers_to_Include=(

	)
	
APSK_Debug____Function_Headers_to_Exclude=(

	)

# 2020-09-27 14:51:21.  Used to determine whether
# Decho____Back_In_This_Function should be allowed to run.

APSK_Debug____Back_In_Function_Headers_to_Include=(

	)
	
APSK_Debug____Back_In_Function_Headers_to_Exclude=(

	)
	

# 2020-09-07 23:22:42.  Used to determine whether
#Decho____Now_Exiting_This_Function should be allowed to run. 
	
APSK_Debug____Function_Footers_to_Include=(
	
	)
	
APSK_Debug____Function_Footers_to_Exclude=(

	)
	
#
#
# 2020-09-08 02:32:28.
#
# 	End of APSK Bash Debugging Library config -
#
# Copy-and-pasteable, developer-settable config vars
# and arrays.
#
# You shouldn't edit them here - you should copy and paste
# them into your own program and edit them there.
#
#
#-------------------------------------------------------------------------------------------------------------------


# 2020-09-08 02:31:06.  Not developer-settable, used by APSK Bash Debugging Library:

APSK_Debug____All_Unique_Tags_Used=()



#-------------------------------------------------------------------------------------------------------------------
#
# *(*)*
#
#	2020-09-08 22:29:37.  Functions especially intended for the developer.
#
#
# 2020-09-08 17:50:35.  Most of these functions accept a tag argument,
# to make it easier to control whether it gets run or displayed or not.
#
#
#--------------------------------------------------
#
# 2020-09-08 17:49:13.  2020-09-09 04:13:39.  2020-12-04 18:26:37.
#
# 7 general printing functions:
#
#
# decho: Debug echo, with source location header
#
# ardecho: Debug-echo an array, with source location header
#
# hashdecho: Debug-echo a hash (an associative array), with source location header
#
#
# APSK_Debug____PrintArr: Echo an array without echoing a header, nor other frills.
#		Doesn't accept tags.
#
# APSK_Debug____PrintHash: Echo a hash (an associative array) without echoing a header.
#		Keys and values are labeled and enclosed in single quotes.  Doesn't accept tags.
#
#
# echoar: Like APSK_Debug____PrintArr, but accepts a tag,
# and has an easier to type name.
#
# echohash: Like APSK_Debug____PrintHash, but accepts a tag,
# and has an easier to type name.



############
# Function
decho()
{
	# 2020-09-08 17:50:12.  Debug echo, with a source location header.
	
	
	# 2020-09-12 02:22:23.  5 inrvars in all, 3 here:
	local tag
	local stuff_to_echo
	local result_code
	
	
	# 2020-09-12 00:08:44.  Unlimited inpvars (input vars), 0 outvars.
	#
	# If there's more than 1 inpvar, the last one will be assumed to be a tag.
	#
	# Everything else is assumed to be stuff to echo.
	
	local args=("$@")
	
		APSK_Debug____Process_Decho_Args	args[@]
	
	
			#!!!!
			APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
		
	
	
	# 2020-09-12 02:37:01.  The last 2 inrvars (inner, non-input-arg local vars):
	
	local retval
	local Source_Location
	
	
	#@@@@
	APSK_Debug____Get_Location_in_Source_File
		Source_Location="$retval"
	#@@@@
	
	echo "

--------------------

decho from $Source_Location"

[ ! -z "$tag" ] && echo "
Tag: $tag"

echo "
%%%%%

$stuff_to_echo

^^^^^"


	#!!!!
	return "$?"
}
#readonly -f decho

# End of
# Function
############



############
# Function
ardecho()
{
	# 2020-09-08 17:49:52.  Debug-echo an array, with a source location header.
	
	
	# 2020-09-08 17:43:03.  3 inpvars, 0 outvars:
	local tag="$3"
	
	#2020-09-26 12:34:12.  3 inrvars, 1 here:
	local result_code
	
	
		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	
	local thisarray="$1"
#	local thisarray=("${!1}")
	local message="$2"
	
	
	# 2020-09-08 17:43:34.  Last 2 inrvars:
	local Source_Location
	local retval
	
	
	#@@@@
	APSK_Debug____Get_Location_in_Source_File
		Source_Location="$retval"
	#@@@@
	
	
	echo "

@@@@@@@@@@@@@@@@@@@@

ardecho from $Source_Location"

[ ! -z "$tag" ] && echo "
Tag: $tag"

echo "
Array: $1"

[ ! -z "$message" ] && echo "
Debug message: $message"

echo "

%%%%%
"

	APSK_Debug____PrintArr 	"$thisarray"
	
	
   	echo "
^^^^^^^^^^^^^^^^^^^^"
	
}
#readonly -f ardecho

# End of
# Function
############



############
# Function
hashdecho()
{
	# 2020-09-08 17:49:52.  2020-12-04 17:18:35.
	#
	# Debug-echo a hash (an associative array), with a source location header.


	# 2020-09-08 17:43:03.  3 inpvars, 0 outvars:
	local tag="$3"

	#2020-09-26 12:34:12.  3 inrvars, 1 here:
	local result_code


		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1


	local thisarray="$1"
#	local thisarray=("${!1}")
	local message="$2"


	# 2020-09-08 17:43:34.  Last 2 inrvars:
	local Source_Location
	local retval


	#@@@@
	APSK_Debug____Get_Location_in_Source_File
		Source_Location="$retval"
	#@@@@


	echo "

%%%%%%%%%%%%%%%%%%%%

hashdecho from $Source_Location"

[ ! -z "$tag" ] && echo "
Tag: $tag"

echo "
Hash: $1"

[ ! -z "$message" ] && echo "
Debug message: $message"

echo "

%%%%%"

	APSK_Debug____PrintHash 	"$thisarray"


	echo "

^^^^^^^^^^^^^^^^^^^^"

}
#readonly -f hashdecho

# End of
# Function
############



############
# Function
echoar()
{
	# 2020-09-11 02:35:36.  Prints an array, but without frills
	# such as a source location header.
	# 
	# Accepts a tag.
	
	
	# 2020-09-11 02:45:29.  Example call of this function:
	#
	# 	echoar	My_Array[@]
	#
	#
	# Or, to run it silently:
	#
	#	result=$(echoar		My_Array[@] )
	
	
	# 2020-09-11 02:36:26.  2 inpvars, 0 outvars, 1 inrvar:
	local tag="$2"
	
	local result_code
	
	
		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	local thisarray="$1"
	
	
	APSK_Debug____PrintArr "$thisarray"

}
#readonly -f echoar

# End of
# Function
############



############
# Function
echohash()
{
	# 2020-09-11 02:35:36.  2020-12-04 18:29:38.
	#
	# Prints a hash (an associative array) without a source location header.
	# Keys and values are labeled and enclosed in single quotes.
	#
	# Accepts a tag.


	# 2020-09-11 02:45:29.  2020-12-04 18:30:41.
	#
	# Example call of this function:
	#
	# 	echohash	My_Hash
	#
	#
	# Or, to run it silently:
	#
	#	result=$(echohash		My_Hash )


	# 2020-09-11 02:36:26.  2 inpvars, 0 outvars, 1 inrvar:
	local tag="$2"

	local result_code


		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1

	local thisarray="$1"


	APSK_Debug____PrintHash "$thisarray"

}
#readonly -f echohash

# End of
# Function
############



############
# Function
APSK_Debug____PrintArr()
{	
	# 2020-09-06 21:17:39.  Example call of this function:
	#
	# 	APSK_Debug____PrintArr	My_Array[@]
	#
	#
	# Or, to run it silently:
	#
	#	result=$(APSK_Debug____PrintArr		My_Array[@] )
	
	
	# 2020-09-08 17:32:49.  1 inpvar, 0 outvars, 0 inrvars:

	local thisarray=("${!1}")
	
	printf '"%s"\n\n' "${thisarray[@]}"

}
#readonly -f APSK_Debug____PrintArr

# End of
# Function
############



# 2020-12-04 17:21:37.  This showed me how to deal with hashes (associative arrays):
#
#https://stackoverflow.com/questions/4069188/how-to-pass-an-associative-array-as-argument-to-a-function-in-bash/32536571#32536571



############
# Function
APSK_Debug____PrintHash()
{
	# 2020-09-06 21:17:39.  2020-12-04 17:20:31.
	#
	# Example call of this function:
	#
	# 	APSK_Debug____PrintHash	My_Hash
	#
	#
	# Or, to run it silently:
	#
	#	result=$(APSK_Debug____PrintHash		My_Hash )


	#echo "now in APSK_Debug____PrintHash"

	#2020-12-04 17:36:28.  1 inpvar, 0 outvars:

	local hash_definition=$( declare -p "$1" )
		#echo; echo; echo "hash_definition: $hash_definition"


	# 2020-12-04 17:37:07.  3 inrvars:

	local hash
	local command_line
	local key


	command_line="declare -A hash=${hash_definition#*=}"
		#echo "command_line: $command_line"

	eval "$command_line"


	for key in "${!hash[@]}"
	do
		echo
		echo
		echo "Key '$key' value:

	\"${hash[$key]}\""
	done
}
#readonly -f APSK_Debug____PrintHash

# End of
# Function
############



#
#
# 2020-09-08 18:17:22.  2020-12-04 18:26:56.
#
# End of 7 general printing functions for the developer.
#
#
#--------------------------------------------------
#
# *(*)*
#
# 2020-09-09 04:18:51.  3 function-announcement functions for the developer:
#
#
# Decho____Now_In_This_Function
# Decho____Back_In_This_Function
# Decho____Now_Exiting_This_Function



############
# Function
Decho____Now_In_This_Function()
{
	# 2020-09-12 02:23:30.  4 inrvars total, 3 here:
	local tag
	local stuff_to_echo
	local result_code
	
	
	# 2020-09-12 00:31:26.  Unlimited inpvars (input vars), 0 outvars.
	#
	# If there's more than 1 inpvar, the last one will be assumed to be a tag.
	#
	# Everything else is assumed to be stuff to echo.
	
	
	local args=("$@")
	
		APSK_Debug____Process_Decho_Args	args[@]
	
	
			#!!!!
			APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	
	# 2020-09-12 02:36:22.  The last inrvar:
	
	local Function_Name
	
	
	Function_Name="${FUNCNAME[1]}"
	
	echo "
	


----------------------------------------------------------------------"
	echo
	echo "Now in $Function_Name()"
	
	
[ ! -z "$tag" ] && echo "
Tag: $tag"

		
	if [ ! -z "$stuff_to_echo" ]
	then
		echo "
Debug message: $stuff_to_echo"
	fi
	
	echo
	echo
	
	
	#!!!!
	return 0
}
#readonly -f Decho____Now_In_This_Function

# End of
# Function
############



############
# Function
Decho____Back_In_This_Function()
{
	
	# 2020-09-12 02:24:23.  4 inrvars total, 3 here:
	local tag
	local stuff_to_echo
	local result_code
	
	
	# 2020-09-12 00:32:26.  Unlimited inpvars (input vars), 0 outvars.
	#
	# If there's more than 1 inpvar, the last one will be assumed to be a tag.
	#
	# Everything else is assumed to be stuff to echo.
	
	
	local args=("$@")
	
		APSK_Debug____Process_Decho_Args	args[@]
	
	
			#!!!!
			APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	
	
	# 2020-09-12 02:36:12.  The last inrvar:
	
	local Function_Name
	
	Function_Name="${FUNCNAME[1]}"
	
	echo -n "
	


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Back in $Function_Name()"

[ ! -z "$tag" ] && echo "	Tag: $tag"


	if [ ! -z "$stuff_to_echo" ]
	then
		echo "

Debug message: $stuff_to_echo"
	fi
	
	echo
	echo
		
	
	#!!!!
	return 0
}
#readonly -f Decho____Back_In_This_Function

# End of
# Function
############



############
# Function
Decho____Now_Exiting_This_Function()
{
	# 2020-09-11 02:12:56.  Optionally, this can print
	# a custom message, and/or announce the return code
	# the function is about to return.
	#
	# Announces the function which the caller of Decho____Now_Exiting_This_Function
	# is about to return to.
	
	
	# 2020-09-12 02:25:20.  6 inrvars total, 4 here:
	local tag
	local stuff_to_echo
	local return_code
	local result_code
	
	
	# 2020-09-12 00:35:42.  Unlimited inpvars (input vars), 0 outvars.
	#
	# 2020-09-12 00:35:37.  The 1st arg is always assumed to be
	# $return_code, which will be printed and also returned.
	#
	# (However, this function can't stop its parent function from continuing
	# after this is run, so you'll have to stop the parent function yourself by
	# always putting a return or exit command after the
	# Decho____Now_Exiting_This_Function command.)
	#
	# If there are more than 2 inpvars, the last one will be assumed to be a tag.
	#
	# Everything else is assumed to be stuff to echo.
	
	
	local args=("$@")
	
		APSK_Debug____Process_Args_for_Decho_Function_Footer	args[@]
	
	
			#!!!!
			APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
		
	
	
	# 2020-09-12 02:35:59.  The last 2 inrvars:	
	
	local Function_Name
	local Parent_Function_Name


	Function_Name="${FUNCNAME[1]}"
	Parent_Function_Name="${FUNCNAME[2]}"

	echo "




----------

Now exiting this function:
	$Function_Name()"

[ ! -z "$tag" ] && echo "
Tag: $tag"


	if [ ! -z "$stuff_to_echo" ]
	then
		echo "

Debug message:

%%%%%

$stuff_to_echo

^^^^^


Still exiting this function:
	$Function_Name()"

	fi


	echo
	if [ ! -z "$return_code" ]
	then
		
		echo "Returning $return_code to:"
	else
		echo "Returning to:"
	fi
	echo "	$Parent_Function_Name()"
	echo
	echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"

	
	#!!!!
	[ ! -z "$return_code" ] && return "$return_code"
	
	
	#!!!!
	return 0
}
#readonly -f Decho____Now_Exiting_This_Function

# End of
# Function
############


#
#
# 2020-09-09 04:21:02.  
#
# End of 3 function-announcement functions for the developer.
#
#
#--------------------------------------------------
#
# *(*)*
#
#	2020-09-10 03:08:45.  5 more functions for the developer:
#
#
#	APSK_Debug____Print_All_Unique_Tags_Used: 
#
#		Lets you know what debug tags your program used so far.
#
#
#	backtrace
#	bt
#	forthtrace
#	ft



############
# Function
APSK_Debug____Print_All_Unique_Tags_Used()
{
	# 2020-09-08 18:21:28.  1 inpvar, 0 outvars, 1 inrvar.
	
	local tag="$1"
	
	local result_code
	
	
		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	
	echo; echo; echo; echo "---------"; echo "APSK Debug: now printing all unique tags used:"
	echo
	APSK_Debug____PrintArr 	APSK_Debug____All_Unique_Tags_Used[@] 
	
	echo
	echo "^^^^^"
	echo
}
#readonly -f APSK_Debug____Print_All_Unique_Tags_Used

# End of
# Function
############



############
# Function
techo()
{
	tagged_echo "$@"
}
#readonly -f techo

# End of
# Function
############



############
# Function
tagged_echo()
{
	# 2020-11-01 11:07:03.  Like decho() minus most of the clutter
	# (such as a source location header) surrounding what you echo.
	#
	# However, if you provide more than one $stuff_to_echo arg,
	# newlines are inserted between them.
	
	
	# 2020-09-12 02:22:23.  4 inrvars in all, 3 here:
	local tag
	local stuff_to_echo
	local result_code
	
	
	# 2020-09-12 00:08:44.  Unlimited inpvars (input vars), 0 outvars.
	#
	# If there's more than 1 inpvar, the last one will be assumed to be a tag.
	#
	# Everything else is assumed to be stuff to echo.
	
	local args=("$@")
	
		APSK_Debug____Process_Decho_Args	args[@]
	
			#!!!!
			APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
			
	
	
	echo "$stuff_to_echo"
}
#readonly -f tagged_echo

# End of
# Function
############



############
# Function
teval()
{
	tagged_eval "$@"
}
#readonly -f teval

# End of
# Function
############



############
# Function
tagged_eval()
{
	local tag="$2"
	
	local result_code
	

		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	
	local command_line="$1"
	
	eval "$command_line"
}
#readonly -f tagged_eval

# End of
# Function
############



############
# Function
dexit()
{

	# 2020-09-11 02:12:56.  2020-10-30 11:35:00.
	#
	# Announces the location at which the entire program is being exited.
	#
	# Optionally, this can print a custom message.
	
	
	# 2020-10-30 11:37:25.  8 inrvars total, 5 here:
	local tag
	local stuff_to_echo
	local return_code
		local exit_code
	local result_code
	
	
	# 2020-09-12 00:35:42.  Unlimited inpvars (input vars), 0 outvars.
	#
	# 2020-10-30 11:36:51.  The 1st arg is always assumed to be
	# $return_code, which will be used as $exit_code.
	#
	# If there are more than 2 inpvars, the last one will be assumed to be a tag.
	#
	# Everything else is assumed to be stuff to echo.
	
	
	# 2020-10-30 12:25:46.  1 more inrvar:
	
	local args=("$@")
	
		APSK_Debug____Process_Args_for_Decho_Function_Footer	args[@]
	
	
			#!!!!
			APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	
	# 2020-09-12 02:37:01.  The last 2 inrvars (inner, non-input-arg local vars):
	
	local retval
	local Source_Location
	
	
	#@@@@
	exit_code="$return_code"
	
	[ -z "$exit_code" ] && exit_code=255
	
	APSK_Debug____Get_Location_in_Source_File
		Source_Location="$retval"
	#@@@@
	

	
	msg="

!!!!!!!!!!!!!!!!!!!!

dexit from $Source_Location

Exit code: $exit_code"

[ ! -z "$tag" ] && msg+="
Tag: $tag"

[ ! -z "$stuff_to_echo" ] && msg+="

%%%%%

$stuff_to_echo

^^^^^

End of dexit from $Source_Location

Exit code: $exit_code
"


	echo "$msg"


	#!!!!
	exit "$exit_code"
}
#readonly -f dexit

# End of
# Function
############



############
# Function
backtrace()
{
	local tag="$4"
	
	local result_code
	

		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	local quantity_to_breve_at_start="$1"
	local quantity_to_breve_at_end="$2"
	local max_unbreved_entries="$3"
	
	backtrace_or_forthtrace "Back" "$quantity_to_breve_at_start" "$quantity_to_breve_at_end" "$max_unbreved_entries"

}
#readonly -f backtrace

# End of
# Function
############



############
# Function
bt()
{
	local tag="$4"
	
	local result_code
	

		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	local quantity_to_breve_at_start="$1"
	local quantity_to_breve_at_end="$2"
	local max_unbreved_entries="$3"
	
	backtrace_or_forthtrace "Back" "$quantity_to_breve_at_start" "$quantity_to_breve_at_end" "$max_unbreved_entries"

}
#readonly -f bt

# End of
# Function
############



############
# Function
forthtrace()
{
	local tag="$4"
	
	local result_code
	

		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	local quantity_to_breve_at_start="$1"
	local quantity_to_breve_at_end="$2"
	local max_unbreved_entries="$3"
	
	backtrace_or_forthtrace "Forth" "$quantity_to_breve_at_start" "$quantity_to_breve_at_end" "$max_unbreved_entries"
	
}
#readonly -f forthtrace

# End of
# Function
############



############
# Function
ft()
{
	local tag="$4"
	
	local result_code
	

		#!!!!
		APSK_Debug____If_Necessary__Quit_This_Debug_Func "$tag"; result_code="$?"; [ "$result_code" = 0 ] && return 1
	
	local quantity_to_breve_at_start="$1"
	local quantity_to_breve_at_end="$2"
	local max_unbreved_entries="$3"
		
	backtrace_or_forthtrace "Forth" "$quantity_to_breve_at_start" "$quantity_to_breve_at_end" "$max_unbreved_entries"
	
}
#readonly -f ft

# End of
# Function
############



#
#
# 2020-09-08 22:06:34.  
#
#
# End of functions especially intended for use by the developer.
#
#
#-------------------------------------------------------------------------------------------------------------------
#
#
# 2020-09-08 18:18:26.  The rest of these functions are used internally.
#
# 2020-09-09 05:42:01.  But the developer can use them if per wants.
#
#		https://stallman.org/articles/genderless-pronouns.html



############
# Function
APSK_Debug____Process_Decho_Args()
{
	# 2020-09-11 23:51:46.  Used by 3 functions:
	#
	#	decho
	#	Decho____Now_In_This_Function
	#	Decho____Back_In_This_Function
	#
	#
	# 2020-09-12 00:29:38.  But not Decho____Now_Exiting_This_Function(),
	# since it was too different from the others.
	
	
	# 2020-09-09 22:00:32.  2020-09-12 00:03:21.
	#
	# If there's more than one arg, the last arg s assumed to be a tag,
	# which will be placed in $tag.
	#
	# All other args get added to $stuff_to_echo.
	
	
	# 2020-09-11 23:50:58.  1 inpvar:
	local args=("${!1}")
	
	
	# 2020-09-11 23:51:13.  2 outvars:
	tag=""
	stuff_to_echo=""

	
	# 2020-09-11 23:51:27.  2 inrvars:
	local count_of_args
	local inc

	
	count_of_args="${#args[@]}"

#ardecho args[@]
		
	if [[ "$count_of_args" -lt 2 ]]
	then
		tag=""
	else
		tag="${args[@]: -1}"
	fi


	if [[ "$count_of_args" = 1 ]]
	then
		[ ! -z "${args[0]}" ] && stuff_to_echo+="${args[0]}"


		#!!!!
		return 0
	fi

	inc=0


	for arg in "${args[@]}"
	do
		let "inc++"
		[[ "$inc" -eq "count_of_args" ]] && break
		
		[[ "$inc" -gt 1 ]] && stuff_to_echo+="

"
		
		stuff_to_echo+="$arg"

	done
	

}
#readonly -f APSK_Debug____Process_Decho_Args

# End of
# Function
############



############
# Function
APSK_Debug____Process_Args_for_Decho_Function_Footer()
{
	# 2020-09-12 00:23:26.  2020-10-30 11:33:00.
	#
	# Used by 2 functions:
	#
	#	Decho____Now_Exiting_This_Function
	#	dexit
	
	
	# 2020-09-09 22:00:32.  2020-09-12 00:03:21.
	# 2020-09-12 00:24:41.
	#
	# The 1st arg is always used as $return_code.
	#
	# If there are more than 2 args, the last arg is assumed to be a tag,
	# which will be placed in $tag.
	#
	# All other args get added to $stuff_to_echo.
	
	
	# 2020-09-11 23:50:58.  1 inpvar:
	local args=("${!1}")
	
	
	# 2020-09-11 23:51:13.  3 outvars:
	tag=""
	stuff_to_echo=""
	return_code=""	
	
	
	# 2020-09-11 23:51:27.  2 inrvars:
	local count_of_args
	local inc
	

	count_of_args="${#args[@]}"
	
		
	if [[ "$count_of_args" -lt 3 ]]
	then
		tag=""
	else
		tag="${args[@]: -1}"
	fi

	
	return_code="${args[0]}"
	
	
	if [[ "$count_of_args" = 1 ]]
	then


		#!!!!
		return 0
	fi
	
	if [[ "$count_of_args" = 2 ]]
	then
		return_code="${args[0]}"
		[ ! -z "${args[1]}" ] && stuff_to_echo+="${args[1]}"
		
		
		#!!!!
		return 0
	fi
	
	
	inc=0
	
	for arg in "${args[@]}"
	do
		let "inc++"
		case "$inc" in
			
			0|1)
				#>>>>
				continue
				;;
				
			"$count_of_args")
				
				break;
				;;
		esac
		
	#	[[ "$inc" -eq "count_of_args" ]] && break
		[[ "$inc" -gt 2 ]] && stuff_to_echo+="

"

		stuff_to_echo+="$arg"
	done


}
#readonly -f APSK_Debug____Process_Args_for_Decho_Function_Footer

# End of
# Function
############



############
# Function
APSK_Debug____For_Trace____Get_Details_about_Function_Call()
{
	local arrin="$1"
	local parent_arrin="$2"
	
	Function_Name="${FUNCNAME[$arrin]}"
	Line_Number="${BASH_LINENO[$arrin]}"
	Func_Fillepath="${BASH_SOURCE[$arrin]}"
		Func_Filename=$(basename "$Func_Fillepath")
			Func_Follpath=$(dirname "$Func_Fillepath")
			Func_Follpath=$(realpath "$Func_Follpath")
			
			
	#	APSK_Debug____Path_to_Htap "$Func_Follpath"
	#		func_foll_htap="$retval"
		
		
	Parent_Function="${FUNCNAME[$parent_arrin]}"
	Parent_Fillepath="${BASH_SOURCE[$parent_arrin]}"
		Parent_Filename=$(basename "$Parent_Fillepath")
		Parent_Follpath=$(dirname "$Parent_Fillepath")
			Parent_Follpath=$(realpath "$Parent_Follpath")
			
		APSK_Debug____Path_to_Htap "$Parent_Follpath"
			parent_foll_htap="$retval"
}
#readonly -f APSK_Debug____For_Trace____Get_Details_about_Function_Call

# End of
# Function
############



############
# Function
backtrace_or_forthtrace()
{
	# 2020-09-10 04:37:05.  Used by both bt()/backtrace() and ft()/forthtrace().
	#
	# Displays a list of the functions called before this function was called.
	#
	# Backtrace: most recent -> least recent.
	# Forthtrace: least recent -> most recent.
	#
	# 2020-09-11 02:21:48.  Tries to exclude itself from the list.
	

	# 2020-09-10 08:29:15.  4 inpvars, 0 outvars:
	local back_or_forth="$1"
	local quantity_to_breve_at_start="$2"
	local quantity_to_breve_at_end="$3"
	local max_unbreved_entries="$4"
	 
	#[ "$max_unbreved_entries" = 0 ] && max_unbreved_entries=""
	[ "$quantity_to_breve_at_start" = 0 ] && quantity_to_breve_at_start=""
	[ "$quantity_to_breve_at_end" = 0 ] && quantity_to_breve_at_end=""
	
	
	# 2020-09-10 19:57:23.  27 inrvars in all - 4 below and 23 later:
	
	local Function_Which_Called_bt_or_ft
		
	local count_of_funcs
		local count_of_funcs_minus_1

	local Header_Text

	
	#@@@@
	[ -z "$back_or_forth" ] && back_or_forth="Back"
	
	Function_Which_Called_bt_or_ft="${FUNCNAME[1]}"

	count_of_funcs="${#FUNCNAME[@]}"
		count_of_funcs_minus_1="$count_of_funcs"
			let "count_of_funcs_minus_1--"
	#@@@@


	# echo "Function_Which_Called_bt_or_ft: $Function_Which_Called_bt_or_ft"

	#APSK_Debug____PrintArr  FUNCNAME[@]
	
	# echo
	# APSK_Debug____PrintArr BASH_LINENO[@]
	
	# echo 
	# APSK_Debug____PrintArr BASH_SOURCE[@]

	
#	echo "count of funcs: $count_of_funcs"
#	echo "quantity_to_breve_at_start: $quantity_to_breve_at_start"
	
	echo
	echo
	echo "========================================"
	echo
	Header_Text="${back_or_forth}trace"
	
	
	[ ! -z "$max_unbreved_entries" ] && Header_Text+=", printing max $max_unbreved_entries unabreved function"
	[[ "$max_unbreved_entries" -gt 1 ]] && Header_Text+="s"
	
	
	[ ! -z "$quantity_to_breve_at_start" ] && Header_Text+=", abreving first $quantity_to_breve_at_start function"
	[[ "$quantity_to_breve_at_start" -gt 1 ]] && Header_Text+="s"
	
	
	[ ! -z "$quantity_to_breve_at_end" ] && Header_Text+=", abreving last $quantity_to_breve_at_end"
	
	
	Header_Text+=":"
	
	echo "$Header_Text"
	echo


	# 2020-09-10 08:52:25.  4 more inrvars, with 19 more remaining:
	
	local arrin
	local parent_arrin
	local origin_arrin
	local breve_at_end_arrin
	
	
	if [ "$back_or_forth" = "Back" ]
	then
		
		breve_at_end_arrin=$(( count_of_funcs - quantity_to_breve_at_end ))
		let "breve_at_end_arrin--"
		
		# 2020-09-10 02:46:38.  Backtrace starts near the beginning
		# of the FUNCNAME array, forthtrace starts near the end.
		case "$Function_Which_Called_bt_or_ft" in
			"backtrace"|"bt")
				arrin=2
				parent_arrin=3
				;;
			
			*)
				arrin=0
				parent_arrin=1
				;;
		esac
		
	else
		# 2020-09-10 01:35:07.  Forth.
		arrin="$count_of_funcs"
		
		
		case "$Function_Which_Called_bt_or_ft" in
			"forthtrace"|"ft")
				let "arrin--"
				origin_arrin=2
			#	let "arrin--"
			#	let "arrin--"
			#	echo "arrin now: $arrin"
				;;
			
			*)
				let "arrin--"
				origin_arrin=1
				;;
		esac
		
		breve_at_end_arrin=$(( origin_arrin + quantity_to_breve_at_end ))
		#let "breve_at_end_arrin++"
		
		
		parent_arrin="$arrin"
		let "parent_arrin++"
	fi
	
	
	# 2020-09-10 08:53:47.  8 more inrvars, with 11 remaining.
	local count_of_entries
	local count_of_entries_printed
		
	local keep_going
	local Origin
	local should_print_long_entry
	
	local entry
	local abreved_entry
	local entries
	
	
	#@@@@
	count_of_entries=0
	count_of_entries_printed=0
	keep_going=true
	Origin=""
	should_print_long_entry=true
	#@@@@
	
	
	# 2020-09-10 08:56:02.  The last 11 inrvar declarations.
	
	local Function_Name
	local Line_Number
	local Func_Fillepath
		local Func_Filename
		local Func_Follpath
			local func_foll_htap
	
	local Parent_Function
	local Parent_Fillepath
		local Parent_Filename
		local Parent_Follpath
		local parent_foll_htap
		
	
	while [ "$keep_going" = true ]
	do
		
		should_print_long_entry=true

		APSK_Debug____For_Trace____Get_Details_about_Function_Call "$arrin" "$parent_arrin"
	
			entry="$Parent_Function() -> $Function_Name() <- Line $Line_Number of $Parent_Filename"
		
			abreved_entry="$Parent_Function() -> $Function_Name() <- Line $Line_Number <- $Parent_Filename"
			#abreved_entry="$Parent_Function() -> $Function_Name()"
			#abreved_entry="$entry"

		if [ "$count_of_entries" -gt 0 ]
		then
			entry="

-------

$entry"

		fi


		if [ "$back_or_forth" = "Back" ]
		then
			if [ -z "$Origin" ]
			then			
			
				Origin="$Parent_Function() -> $Function_Name() <- Line $Line_Number of $Parent_Filename"
			
				echo "$Origin"
				echo
				echo "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
			
"
			else
				# 2020-09-10 05:13:42.  Origin has already been printed for backtrace.
				
				if [ ! -z "$max_unbreved_entries" ]
				then
	
					[[ "$count_of_entries_printed" -ge "$max_unbreved_entries" ]] && should_print_long_entry=false
				
				fi
				
				if [ "$should_print_long_entry" = true ]
				then

					if [ ! -z "$quantity_to_breve_at_start" ]
					then
						[[ "$count_of_entries" -lt "$quantity_to_breve_at_start" ]] &&	should_print_long_entry=false

					fi
				fi
				
				if [ "$should_print_long_entry" = true ]
				then
			
					if [ ! -z "$quantity_to_breve_at_end" ]
					then
						
						[[ "$arrin" -ge "$breve_at_end_arrin" ]] && should_print_long_entry=false

					fi
				fi
				
				if [ "$should_print_long_entry" = true ]
				then
					echo "$entry"
					let "count_of_entries_printed++"
				else
					# 2020-09-11 02:25:13.  If the long entry doesn't get printed,
					# the indented, just slightly abreved entry is printed instead.
					echo "
	---

	$abreved_entry"
				fi
				
			
				let "count_of_entries++"
			fi
		
			let "arrin++"
			let "parent_arrin++"
			
			
			[ "$arrin" -eq "$count_of_funcs_minus_1" ] && { keep_going=false; continue; }
			
		else
			# 2020-09-10 02:10:04.  Forth
		
			if [ "$arrin" -eq "$origin_arrin" ]
			then
			
				Origin="$Parent_Function() -> $Function_Name() <- Line $Line_Number of $Parent_Filename"
			
				echo "$Origin"
				echo
				echo "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
				echo
				echo
				echo "$entries"
			
				keep_going=false
			
			
				#>>>>
				continue
			else
				if [ "$arrin" -gt 1 ]
				then
					
				
					if [ ! -z "$max_unbreved_entries" ]
					then
		
						[[ "$count_of_entries_printed" -ge "$max_unbreved_entries" ]] && should_print_long_entry=false					
					fi
					
					if [ "$should_print_long_entry" = true ]
					then
					
						if [ ! -z "$quantity_to_breve_at_start" ]
						then
							[[ "$count_of_entries" -lt "$quantity_to_breve_at_start" ]] &&	should_print_long_entry=false

						fi
					fi
					
					if [ "$should_print_long_entry" = true ]
					then
					
						if [ ! -z "$quantity_to_breve_at_end" ]
						then
							
							[[ "$arrin" -le "$breve_at_end_arrin" ]] &&	should_print_long_entry=false

						fi
					fi
					
					
					if [ "$should_print_long_entry" = true ]
					then
						entries+="
$entry"
						let "count_of_entries_printed++"
					else
						entries+="

	---

	$abreved_entry"
					fi
			
					let "count_of_entries++"
				fi
			fi
		
			let "arrin--"
			let "parent_arrin--"
			
			[[ "$parent_arrin" -eq 0 ]] && parent_arrin=1
		fi

	done

		
		
	echo
	echo
	echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
	echo
#	echo "End of ${back_or_forth}trace:"
	echo "End of $Header_Text"
	echo
	echo "$Origin"
	echo
	echo "========================================"
	
}
#readonly -f backtrace_or_forthtrace

# End of
# Function
############



############
# Function
APSK_Debug____Get_Location_in_Source_File()
{
	# 2020-09-08 17:39:19.  0 inpvars
	#
	# 1 outvar: $retval
	#
	# 7 inrvars:
	
	local Function_Name
	local Line_Number
	local Source_Fillepath
		local Source_Filename
		local Source_Follpath
			local foll_htap
				local location
	
	
	#@@@
	Function_Name="${FUNCNAME[2]}"
	Line_Number="${BASH_LINENO[1]}"
	
	Source_Fillepath="${BASH_SOURCE[2]}"
		Source_Filename=$(basename "$Source_Fillepath")
		Source_Follpath=$(dirname "$Source_Fillepath")
			Source_Follpath=$(realpath "$Source_Follpath")
	#@@@@
	
	
	APSK_Debug____Path_to_Htap "$Source_Follpath"
		foll_htap="$retval"
	
			location="$Function_Name() -> Line $Line_Number <- $Source_Filename
	
	$foll_htap"
	
	retval="$location"
	
	
	#!!!!
	return 0
}
#readonly -f APSK_Debug____Get_Location_in_Source_File

# End of
# Function
############



############
# Function
APSK_Debug____Path_to_Htap()
{
	# 2020-09-08 22:10:55.  1 inpvar:
	local path="$1"
	
	# 2020-09-08 22:11:21.  1 outvar:
	retval=""
	
	
	# 2020-09-08 22:11:31.  2 inrvars:
	
	local htap
	local Array____htap
	
	
	IFS=/ read -a Array____htap <<< "$path"
	
	htap=$(printf '%s\n' "${Array____htap[@]}" | tac | tr '\n' '\\')
	
	
		retval="$htap"
	
	
	#!!!!
	return 0
}
#readonly -f APSK_Debug____Path_to_Htap

# End of
# Function
############



############
# Function
APSK_Debug____Check_Array_for_String()
{
	# 2020-09-06 22:57:39.  Example call of this function:
	#
	# 	APSK_Debug____Check_Array_for_String	"string"		My_Array[@]
	
	
	# 2020-09-06 23:09:28.
	#
	# Return codes:
	#
	# 0: string found
	# 1: string not found
	
	
	# 2020-09-06 22:57:43.  2 inpvars, 0 outvars:

	local string="$1"
	local thisarray=("${!2}")
	
	
	# 2020-09-07 01:43:28.  1 inrvar:
	local item
	
	
	#!!!!
	[ ${#thisarray[@]} -eq 0 ] && return 1
	
	
	
	#inc=0
	for item in "${thisarray[@]}"
	do
		#echo "inc: $inc"
		#echo "string: $string"
		#echo "item: $item"
		#let "inc++"
		if [ "$string" = "$item" ]
		then
		
			#echo "String=item!"
			
			
			#!!!!
			return 0
		fi
	done
	
	
	#!!!!
	return 1
}
#readonly -f APSK_Debug____Check_Array_for_String

# End of
# Function
############



############
# Function
APSK_Debug____See_if_New_Array_Item_is_Unique()
{
	# 2020-09-07 02:21:56.
	#
	# Return codes:
	#
	# 0: unique
	# 1: not unique
	
	
	# 2020-09-09 06:07:38.  2 inpvars, 0 outvars:
	
	local item="$1"
	local thisarray=("${!2}")
	
	
	# 2020-09-09 06:07:53.  1 inrvar:
	local old_item


	#!!!!
	[ ${#thisarray[@]} -eq 0 ] && return 0
	
	
	
	for old_item in "${thisarray[@]}"
	do
		if [ "$old_item" = "$item" ]
		then
			
			
			#!!!!
			return 1			
		fi
	done
	
	
	#!!!!
	return 0
}
#readonly -f APSK_Debug____See_if_New_Array_Item_is_Unique

# End of
# Function
############



############
# Function
APSK_Debug____Note_Unique_Tag()
{

	# 2020-09-09 07:10:21.
	#
	# Return codes:
	#
	# 0 = noted a tag
	# 1 = didn't note a tag
	
	
	# 2020-09-09 07:09:41.   1 inpvar, 0 outvars:
	
	local tag="$1"
	#local thisarray=("${!2}")
	
	
	# 2020-09-09 07:10:04.  1 inrvar:
	local result_code
	
	
	#!!!!
	#[ -z "$tag" ] && return 1
	
	
	APSK_Debug____See_if_New_Array_Item_is_Unique 	"$tag" 	APSK_Debug____All_Unique_Tags_Used[@]
		result_code="$?"

		
	if [ "$result_code" = 0 ]
	then
	
		APSK_Debug____All_Unique_Tags_Used+=( "$tag" )
		
		
		#!!!!
		return 0
	fi
	
	
	#!!!!
	return 1
}
#readonly -f APSK_Debug____Note_Unique_Tag

# End of
# Function
############



############
# Function
APSK_Debug____If_Necessary__Quit_This_Debug_Func()
{
	# 2020-09-08 22:13:38.  2020-09-11 02:32:35.  2020-10-30 12:17:43.  2020-12-04 19:14:43.
	# 
	# This function gets run at the beginning of most
	# developer-useable debug functions, including:
	#
	# decho
	#
	# ardecho
	# hashdecho
	#
	# echoar
	# echohash
	#
	# APSK_Debug____Print_All_Unique_Tags_Used
	#
	# Decho____Now_In_This_Function
	# Decho____Back_In_This_Function
	# Decho____Now_Exiting_This_Function
	#
	# backtrace
	# bt
	#
	# forthtrace
	# ft
	#
	# tagged_echo (long name for techo)
	#
	# tagged_eval (long name for teval)
	# dexit
	
	

	# 2020-09-07 01:49:56.
	#
	# Return codes:
	#
	# 0: should quit this debug function
	# 1: shouldn't quit

	
	#!!!!
	[ "$APSK_DEBUG_MODE" != true ] && return 0
	
	
	# 2020-09-07 02:02:02.  1 inpvar, 0 outvars:
	
	local tag="$1"
		APSK_Debug____Note_Unique_Tag "$tag"
	
	
	# 2020-09-07 01:48:48.  3 inrvars:
	local Function_Name
	local Debug_Function_Name
	local result_code
	
	
	#@@@@	
	local Function_Name="${FUNCNAME[2]}"
	local Debug_Function_Name="${FUNCNAME[1]}"
	#@@@@

	
	#echo "Debug_Function_Name: $Debug_Function_Name"
	
	case "$Debug_Function_Name" in
	
		"decho")
		
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "decho" "$tag" "$Function_Name"
				result_code="$?"
			;;
		
		#----
		"ardecho")
			
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "ardecho" "$tag" "$Function_Name"
				result_code="$?"
			;;

		#----
		"hashdecho")

			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "hashdecho" "$tag" "$Function_Name"
				result_code="$?"
			;;

		#----
		"echoar")

			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "echoar" "$tag" "$Function_Name"
				result_code="$?"
			;;

		#----					
		"echohash")
			
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "echohash" "$tag" "$Function_Name"
				result_code="$?"
			;;

		#----				
		"APSK_Debug____Print_All_Unique_Tags_Used")
			
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "APSK_Debug____Print_All_Unique_Tags_Used" "$tag" "$Function_Name"
				result_code="$?"
			;;

		#----
		"Decho____Now_In_This_Function")
			
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "Decho____Now_In_This_Function" "$tag" "$Function_Name"
				result_code="$?"
			;;
			
		#----
		"Decho____Back_In_This_Function")
			
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "Decho____Back_In_This_Function" "$tag" "$Function_Name"
				result_code="$?"
			;;
			
		#----				
		"Decho____Now_Exiting_This_Function")
		
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "Decho____Now_Exiting_This_Function" "$tag" "$Function_Name"
				result_code="$?"
			;;
		
		#----	
		"bt"|"backtrace")
		
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "bt" "$tag" "$Function_Name"
				result_code="$?"
			;;
			
		#----
		"ft"|"forthtrace")
		
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "ft" "$tag" "$Function_Name"
				result_code="$?"
			;;
		#----
		"techo"|"tagged_echo")
		
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "techo" "$tag" "$Function_Name"
				result_code="$?"
			;;
		#----
		"teval"|"tagged_eval")
		
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "teval" "$tag" "$Function_Name"
				result_code="$?"
			;;
		#----
		"dexit")
		
			APSK_Debug____Check_if_This_Debug_Function_is_Allowed "dexit" "$tag" "$Function_Name"
				result_code="$?"
			;;		
		#----		
		*)
			APSK_Debug____Console_and_Copyable_Dialog_Box____Error_Message "

APSK Debug: Aborting because the function APSK_Debug____If_Necessary__Quit_This_Debug_Func() was called by a function not recognized as an APSK debug function!

The unrecognized function was:

	$Debug_Function_Name()" "Unusual APSK Debug Error"
			
			
			#!!!!
			exit 199
	esac
	
	
	#!!!!
	[ "$result_code" = 0 ] && return 1
	
	
	#!!!!
	return 0
}
#readonly -f APSK_Debug____If_Necessary__Quit_This_Debug_Func

# End of
# Function
############



############
# Function
APSK_Debug____Check_if_This_Debug_Function_is_Allowed()
{
	# 2020-09-11 02:55:50.  Return codes:
	#
	#	0 - this debug function is allowed
	#	1 - this debug function isn't allowed
	
	
	# 2020-09-08 18:36:08.  3 inpvars, 0 outvars:
	local Debug_Function_Name="$1"
	local tag="$2"
	local Function_Name="$3"
	
	
	# 2020-09-08 18:36:18.  3 inrvars:
	local tag_result_code
	local function_result_code
	local dechoer_result_code
	
	
	case "$Debug_Function_Name" in
		#----
		"decho")
			
			
			#!!!!
			[ "$APSK_Debug____should_allow_decho" != true ] && return 1
			;;
			
		#----
		"ardecho")
			
			
			#!!!!
			[ "$APSK_Debug____should_allow_ardecho" != true ] && return 1
			;;


		#----
		"hashdecho")

			
			#!!!!
			[ "$APSK_Debug____should_allow_hashdecho" != true ] && return 1
			;;

		#----
		"echoar")


			#!!!!
			[ "$APSK_Debug____should_allow_echoar" != true ] && return 1
			;;


		#----
		"echohash")
			
			
			#!!!!
			[ "$APSK_Debug____should_allow_echohash" != true ] && return 1
			;;
			
		#----
		"APSK_Debug____Print_All_Unique_Tags_Used")
			
			
			#!!!!
			[ "$APSK_Debug____should_allow_printing_of_unique_tags" != true ] && return 1
			;;
			
		#----
		"Decho____Now_In_This_Function")
		
		
			#!!!!
			[ "$APSK_Debug____should_print_Now_in_Function_headers" != true ] && return 1
			;;
		
		#----
		"Decho____Back_In_This_Function")
		
		
			#!!!!
			[ "$APSK_Debug____should_print_Back_in_Function_headers" != true ] && return 1
			;;
		
		#----
		"Decho____Now_Exiting_This_Function")
		
		
			#!!!!
			[ "$APSK_Debug____should_print_Now_Exiting_This_Function_footers" != true ] && return 1
			;;

		#----
		"bt"|"backtrace")
		
		
			#!!!!
			[ "$APSK_Debug____should_allow_backtrace" != true ] && return 1
			;;
			
		#----
		"ft"|"forthtrace")
		
		
			#!!!!
			[ "$APSK_Debug____should_allow_forthtrace" != true ] && return 1
			;;
			
		#----
		"techo"|"tagged_echo")
		
		
			#!!!!
			[ "$APSK_Debug____should_allow_tagged_echo" != true ] && return 1
			;;
			
		#----
		"teval"|"tagged_eval")
		
		
			#!!!!
			[ "$APSK_Debug____should_allow_tagged_eval" != true ] && return 1
			;;
			
		#----
		"dexit")
		
		
			#!!!!
			[ "$APSK_Debug____should_allow_dexit" != true ] && return 1
			;;
	esac
	
	
	# 2020-09-27 14:53:30.  Tags have precedence over everything else.
	
	APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Tag "$tag"
		tag_result_code="$?"
	

	#!!!!
	[ "$tag_result_code" != 2 ] && return "$tag_result_code"
		# 2020-09-08 18:40:24.  2020-09-11 02:59:37.
		#
		# If a tag is definitely included, or or definitely excluded, or
		# if there's a tag-include list and this tag was left out of it,
		# we return early without doing function checks.
		#
		# But if a tag doesn't fall into any of those categories -
		# whether the function it's attached to gets run or not
		# depends on the function includes/excludes or lack thereof.

	
	# 2020-09-27 14:54:26.  Next, if this is a debug function which dechoes
	# function headers or footers, we check if it's allowed or not.
	#
	# 2020-09-27 15:41:03.  These header/footer includes/excludes have precedence
	# over the function includes/excludes.
	
	case "$Debug_Function_Name" in
	
		"Decho____Now_In_This_Function"|"Decho____Back_In_This_Function"|"Decho____Now_Exiting_This_Function")
			
			APSK_Debug____Check_if_Debug_Should_Proceed_For_Dechoer_of_Function_Header_or_Footer "$Debug_Function_Name" "$Function_Name"
				dechoer_result_code="$?"
			
			
				#!!!!
				[ "$dechoer_result_code" != 2 ] && return "$dechoer_result_code"
				
			;;
	esac
	
	
	# 2020-09-08 01:32:00.  Next, checking the function arrays.
	
	APSK_Debug____Check_if_Debug_Should_Proceed_Within_This_Function "$Function_Name"
		function_result_code="$?"
	

	#!!!!
	[ "$function_result_code" -lt 2 ] && return 0
		# 2020-09-11 03:00:00.  If the function wasn't excluded,
		# or was in the function-include list, or if there's no
		# function-include list (in which case being left out of the
		# include list has no effect) - this debug function is allowed.
		
	
	# 2020-09-08 01:56:12.  In any other cases, it's a no.
	
	
	#!!!!
	return 1
	
}
#readonly -f APSK_Debug____Check_if_This_Debug_Function_is_Allowed

# End of
# Function
############

	
	
############
# Function
APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Tag()
{
	# 2020-09-08 02:56:28.  Return codes:
	#
	# 0 - calling function should return 1, to immediately proceed
	#
	# 1 - calling function should return 0, to immediately skip this tag
	#
	# 2 - calling function shouldn't return yet, and should do other checks
	# to figure out whether to proceed
	
	
	# 2020-09-11 03:04:10.  1 inpvar, 0 outvars:
	local tag="$1"
	
	# 2020-09-11 03:04:20.  1 inrvar:
	local tag_result_code
	
	
	# 2020-09-08 01:53:07.  First, checking the Tags arrays.	
	
	#echo "Checking tags arrays"
	APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Category "$tag" 	APSK_Debug____Tags_to_Include[@]	APSK_Debug____Tags_to_Exclude[@]
		tag_result_code="$?"

	
	# 2020-09-08 00:02:43.
	#
	# Return codes for tag check above:
	#
	# 0 - probably should proceed -
	#	neither included nor excluded
	#
	# 1 - definitely should proceed -
	#	definitely included
	# 
	# 2 - definitely shouldn't proceed - 
	#	definitely not included
	# 
	# 3 - definitely shouldn't proceed -
	#	definitely excluded

	#echo "tag: '$tag'  tag_result_code: $tag_result_code"
	
	
	#!!!!
	[ "$tag_result_code" = 1 ] && return 0
		# 2020-09-08 01:25:55.  1 = a definite yes for the tag, in which
		# case, it's a definite yes overall without even checking anything else.
	
	#!!!!
	[ "$tag_result_code" = 2 ] && return 1
		# 2020-09-08 02:03:45.  2 = definitely not included, which
		# means there are include tags, which means anything not
		# included should be skipped.
	
	#!!!!
	[ "$tag_result_code" = 3 ] && return 1
		# 2020-09-08 02:08:42.  3 = definitely excluded.
		
	

	# 2020-09-11 03:05:57.  If none of the above applies, other
	# checks need to be done.
	
	
	#!!!!
	return 2
}
#readonly -f APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Tag

# End of
# Function
############



############
# Function
APSK_Debug____Check_if_Debug_Should_Proceed_For_Dechoer_of_Function_Header_or_Footer()
{

	# 2020-09-08 02:56:28.  2020-09-27 15:03:18.
	# 
	# Return codes:
	#
	# 0 - calling function should return 1, to immediately proceed
	#
	# 1 - calling function should return 0, to immediately skip this header or footer
	#
	# 2 - calling function shouldn't return yet, and should do other checks
	# to figure out whether to proceed
	
	
	# 2020-09-27 16:16:09.  2 inpvars, 0 outvars:
	local Debug_Function_Name="$1"
	local Function_Name="$2"
	
	
	# 2020-09-27 16:16:13.  4 inrvars:
	local dechoer_result_code
	local array_prefix
	local array_name____includes
	local array_name____excludes
	
	

	case "$Debug_Function_Name" in
		#----
		"Decho____Now_In_This_Function")
			
			array_prefix="APSK_Debug____Function_Headers"
		#	APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Category "$Function_Name" 	APSK_Debug____Function_Headers_to_Include[@]	APSK_Debug____Function_Headers_to_Exclude[@]
				result_code="$?"
			
			;;
		#----
		"Decho____Back_In_This_Function")
			array_prefix="APSK_Debug____Back_In_Function_Headers"
		
		#	APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Category "$Function_Name" 	APSK_Debug____Back_In_Function_Headers_to_Include[@]	APSK_Debug____Back_In_Function_Headers_to_Exclude[@]
				result_code="$?"
			;;
		
		#----
		"Decho____Now_Exiting_This_Function")
			array_prefix="APSK_Debug____Function_Footers"
		
			#APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Category "$Function_Name" 	APSK_Debug____Back_In_Function_Headers_to_Include[@]	APSK_Debug____Back_In_Function_Headers_to_Exclude[@]
				result_code="$?"
			;;
	esac
	
	
	array_name____includes="${array_prefix}_to_Include[@]"
	array_name____excludes="${array_prefix}_to_Exclude[@]"
	
	
	#echo "array_name____includes: $array_name____includes"
	#echo "array_name____excludes: $array_name____excludes"
	
	APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Category "$Function_Name" 	"$array_name____includes" "$array_name____excludes"
		dechoer_result_code="$?"
	
	
	#echo; echo "$Debug_Function_Name $Function_Name dechoer_result_code: $dechoer_result_code"
	
	
	# 2020-09-08 00:02:43.  2020-09-27 15:43:22.
	#
	# Return codes for the check above:
	#
	# 0 - probably should proceed -
	#	neither included nor excluded
	#
	# 1 - definitely should proceed -
	#	definitely included
	# 
	# 2 - definitely shouldn't proceed - 
	#	definitely not included
	# 
	# 3 - definitely shouldn't proceed -
	#	definitely excluded
	
	
	#!!!!
	[ "$dechoer_result_code" = 1 ] && return 0
		# 2020-09-08 01:25:55.  2020-09-27 15:46:16.
		# 
		# 1 = a definite yes for this dechoer, in which
		# case, it's a definite yes overall without even checking anything else.
	
	#!!!!
	[ "$dechoer_result_code" = 2 ] && return 1
		# 2020-09-08 02:03:45.  2020-09-27 15:46:21.
		# 
		# 2 = definitely not included, which
		# means there are included dechoers, which means anything not
		# included should be skipped.
	
	#!!!!
	[ "$dechoer_result_code" = 3 ] && return 1
		# 2020-09-08 02:08:42.  3 = definitely excluded.
		
	
	# 2020-09-11 03:05:57.  If none of the above applies, other
	# checks need to be done.
	
	
	#!!!!
	return 2
}
#readonly -f APSK_Debug____Check_if_Debug_Should_Proceed_For_Dechoer_of_Function_Header_or_Footer

# End of
# Function
############



############
# Function
APSK_Debug____Check_if_Debug_Should_Proceed_Within_This_Function()
{
	# 2020-09-11 03:06:23. 1 inpvar, 0 outvars:
	
	local Function_Name="$1"
	
	
	# 2020-09-11 03:06:34.  1 inrvar:
	local result_code
	
	
	APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Category "$Function_Name" 	APSK_Debug____Functions_to_Include[@]	APSK_Debug____Functions_to_Exclude[@]
		result_code="$?"
	
	
	#!!!!
	return "$result_code"
}
#readonly -f APSK_Debug____Check_if_Debug_Should_Proceed_Within_This_Function

# End of
# Function
############



############
# Function
APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Category()
{
	# 2020-09-08 00:02:43.
	#
	# Return codes:
	#
	# 0 - probably should proceed -
	#	neither included nor excluded
	#
	# 1 - definitely should proceed -
	#	definitely included
	# 
	# 2 - definitely shouldn't proceed - 
	#	definitely not included
	# 
	# 3 - definitely shouldn't proceed -
	#	definitely excluded
	
	
	# 2020-09-11 03:08:01.  3 inpvars, 0 outvars:

	local string="$1"
	
	local array_of_includes=("${!2}")
	local array_of_excludes=("${!3}")


	# 2020-09-11 03:08:27.  1 inrvar:
	local result_code
	
	
#	echo; echo
#	echo "string: $string 2: $2 3: $3"
#	echo "includes array count: ${#array_of_includes[@]}"
#	echo "excludes array count: ${#array_of_excludes[@]}"
#	echo;	echo

	# 2020-09-07 23:57:50.  If there are no includes or excludes, anything goes.
	
	if [ ${#array_of_includes[@]} -eq 0 ]
	then
	
		if [ ${#array_of_excludes[@]} -eq 0 ]
		then
		
		
			#!!!!
			return 0
		fi
	fi
	

	if [ ${#array_of_includes[@]} -eq 0 ]
	then
		# 2020-09-07 01:58:37.  No strings to include, so we check for strings to exclude.
		APSK_Debug____Check_Array_for_String 	"$string" 	array_of_excludes[@]
			result_code="$?"
		
		
		#!!!!
		[ "$result_code" = 0 ] && return 3
			# 2020-09-07 01:58:47.  Should quit if a string to exclude is found.
		
		
		#!!!!
		return 0
	else
		# 2020-09-07 01:58:52.  There are strings to include, so we ignore anything not included.
		
		APSK_Debug____Check_Array_for_String 	"$string" 	array_of_includes[@]
			result_code="$?"
		
		
		#!!!!
		[ "$result_code" = 0 ] && return 1
			# 2020-09-07 01:59:08.  Shouldn't quit if a string to include is found.
		

		#!!!!
		return 2
	fi
}
#readonly -f APSK_Debug____Check_if_Debug_Should_Proceed_For_This_Category

# End of
# Function
############



###################################
#
#	2020-12-04 18:41:34.
#
#	Stuff originally from APSK Simple Dialog Displayer:
#
#


############
# Function
APSK_Debug____Wrap_Text()
{
	local -r message="$1"
	local -r columns="$2"

	#----
	local wrapped_message


	##############################

	wrapped_message=$(echo "$message" | fold --width $columns --spaces)

	retval="$wrapped_message"
}
#readonly -f APSK_Debug____Wrap_Text

# End of
# Function
############



############
# Function
APSK_Debug____Console____Error_Message()
{
	local -r error_message="$1"
	local -r should_omit_heading="$2"


	##############################

	if [ ! -z "$should_omit_heading" ]
	then
		retval="$error_message"

		>&2 echo "$error_message"


		#!!!!
		return 0
	fi

	#~ retval="$Script_Title error:
#~
#~ $error_message"

	retval="$error_message"

	>&2 echo "$retval"


	#!!!!
	return 0
}
#readonly -f APSK_Debug____Console____Error_Message

# End of
# Function
############



############
# Function
APSK_Debug____Dialog_Box____Copyable_Message()
{

	#!!!!
	[ "$APSK____should_display_GUI_dialog_boxes" = false ] && return 0


	#----
	local -r message="$1"
	local -r title="$2"
	local width="$3"
	local height="$4"

	#@@@@
	[ -z "$width" ] && width=-1
	[ -z "$height" ] && height=-1


	##############################


	echo "$message" | Xdialog --title "$title" --textbox - "$height" "$width"

	case "$?" in
		0)
			#echo "OK"
			;;

		255)
			#echo "Box closed"
			;;
	esac


	#!!!!
	return 0
}
#readonly -f APSK_Debug____Dialog_Box____Copyable_Message

# End of
# Function
############



############
# Function
APSK_Debug____Dialog_Box____Copyable_Error_Message()
{

	#!!!!
	[ "$APSK____should_display_GUI_dialog_boxes" = false ] && return 0


	local -r error_message="$1"
	local -r title="$2"
	local width="$3"
	local height="$4"


	if [ -z "$title" ]
	then
		error_title=""
	fi


	##############################


	APSK_Debug____Dialog_Box____Copyable_Message "$error_message" "$error_title" "$width" "$height"
}
#readonly -f APSK_Debug____Dialog_Box____Copyable_Error_Message

# End of
# Function
############



############
# Function
APSK_Debug____Console_and_Copyable_Dialog_Box____Error_Message()
{
	local -r error_message="$1"
	local error_title="$2"
	local -r width="$3"
	local -r height="$4"


	##############################

	APSK_Debug____Console____Error_Message "$error_message"

	#echo; echo; echo "APSK____should_display_GUI_dialog_boxes: $APSK____should_display_GUI_dialog_boxes"

	#!!!!
	[ "$APSK____should_display_GUI_dialog_boxes" = false ] && return 0

	APSK_Debug____Wrap_Text "$error_message" 80


	APSK_Debug____Dialog_Box____Copyable_Error_Message "$retval" "$error_title" "$height" "$width"


	#!!!!
	return 0
}
#readonly -f APSK_Debug____Console_and_Copyable_Dialog_Box____Error_Message

# End of
# Function
############