########################################################################
#                                                                      #
#               This software is part of the ast package               #
#          Copyright (c) 1982-2012 AT&T Intellectual Property          #
#          Copyright (c) 2020-2024 Contributors to ksh 93u+m           #
#                      and is licensed under the                       #
#                 Eclipse Public License, Version 2.0                  #
#                                                                      #
#                A copy of the License is available at                 #
#      https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html      #
#         (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d)         #
#                                                                      #
#                  David Korn <dgk@research.att.com>                   #
#                  Martijn Dekker <martijn@inlv.org>                   #
#            Johnothan King <johnothanking@protonmail.com>             #
#                  Lev Kujawski <int21h@mailbox.org>                   #
#                                                                      #
########################################################################

. "${SHTESTS_COMMON:-${0%/*}/_common}"

compiled=''
read -n4 c < $0 2> /dev/null
[[ $c == *$'\ck'* ]] && compiled=1

ulimit -c 0

bin_echo=$(whence -p echo)
bin_sleep=$(whence -p sleep)
bin_kill=$(whence -p kill)

# ======
# In ksh93v- and ksh2020 eval'ing a function definition may dump the function body to stdout.
# https://github.com/att/ast/issues/1160
got="$($SHELL -c '
	for ((i=0; i<1025; i++))
	do	str="${str}12345678"
	done
	eval "foo() { $str; }"

	baz() { eval "bar() { FAILURE; }"; }
	( baz >&3 ) 3>&1
')"
[[ -n "$got" ]] && err_exit "eval'ing function dumps function body to stdout" \
	"(got $(printf %q "$got"))"

# ======
# Check for global variables and $0
integer foo=33
bar=bye
function foobar
{
	case $1 in
	1) 	print -r - "$foo" "$bar";;
	2)	print -r - "$0";;
	3)	typeset foo=foo
		integer bar=10
	 	print -r - "$foo" "$bar";;
	4)	trap 'foo=36' EXIT
		typeset foo=20;;
	esac
}
function print
{
	command print hi
}
if	[[ $(print) != hi ]]
then	err_exit "command print not working inside print function"
fi
unset -f print

if	[[ $(foobar 1) != '33 bye' ]]
then	err_exit 'global variables not correct'
fi

if	[[ $(foobar 2) != 'foobar' ]]
then	err_exit '$0  not correct'
fi

if	[[ $(bar=foo foobar 1) != '33 foo' ]]
then	err_exit 'environment override not correct'
fi
if	[[ $bar == foo ]]
then	err_exit 'scoping error'
fi

if	[[ $(foobar 3) != 'foo 10' ]]
then	err_exit non-local variables
fi

foobar 4
if	[[ $foo != 36 ]]
then	err_exit EXIT trap in wrong scope
fi
unset -f foobar || err_exit "cannot unset function foobar"
typeset -f foobar>/dev/null  && err_exit "typeset -f has incorrect exit status"

function foobar
{
	(return 0)
}
> $tmp/test1
{
foobar
if	[ -r $tmp/test1 ]
then	rm -r $tmp/test1
else	err_exit 'return within subshell inside function error'
fi
}
abc() print hi
if	[[ $(abc) != hi ]]
then	err_exit 'abc() print hi not working'
fi
( unset -f abc )
if	[[ $(abc 2>/dev/null) != hi ]]
then	err_exit 'abc() print hi not working after subshell unset'
fi
(
	function f
	{
		exit 1
	}
	f
	err_exit 'exit from function not working'
)
unset -f foo
function foo
{
	x=2
	(
		x=3
		cd $tmp
		print bar
	)
	if	[[ $x != 2 ]]
	then	err_exit 'value of x not restored after subshell inside function'
	fi
}
x=1
dir=$PWD
if	[[ $(foo) != bar ]]
then	err_exit 'cd inside nested subshell not working'
fi
if	[[ $PWD != "$dir" ]]
then	err_exit 'cd inside nested subshell changes $PWD'
fi
fun() "$bin_echo" hello
if	[[ $(fun) != hello ]]
then	err_exit "'fun() simple_command' not working"
fi
cat > $tmp/script <<-\!
	print -r -- "$1"
!
chmod +x $tmp/script
function passargs
{
	$tmp/script "$@"
}
if	[[ $(passargs one) != one ]]
then	err_exit 'passing args from functions to scripts not working'
fi
cat > $tmp/script <<-\!
	trap 'exit 0' EXIT
	function foo
	{
		/tmp > /dev/null 2>&1
	}
	foo
!
if	! $tmp/script
then	err_exit 'exit trap incorrectly triggered'
fi
if	! $SHELL -c $tmp/script
then	err_exit 'exit trap incorrectly triggered when invoked with -c'
fi
$SHELL -c "trap 'rm $tmp/script' EXIT"
if	[[ -f $tmp/script ]]
then	err_exit 'exit trap not triggered when invoked with -c'
fi
cat > $tmp/script <<- \EOF
	foobar()
	{
		return
	}
	shift
	foobar
	print -r -- "$1"
EOF
chmod +x $tmp/script
if	[[ $( $SHELL $tmp/script arg1 arg2) != arg2 ]]
then	err_exit 'arguments not restored by POSIX functions'
fi
function foo
{
	print hello
}
(
	function foo
	{
		print bar
	}
	if [[ $(foo) != bar ]]
	then	err_exit 'function definitions inside subshells not working'
	fi
)
if [[ $(foo) != hello ]]
then	err_exit 'function definitions inside subshells not restored'
fi
unset -f foo bar
function bar
{
        print "$y"
}

function foo
{
        typeset x=3
        y=$x bar
}
x=1
if	[[ $(foo) != 3 ]]
then	err_exit 'variable assignment list not using parent scope'
fi
unset -f foobar
cat > $tmp/foobar <<!
function foobar
{
	print foo
}
!
chmod +x $tmp/foobar
FPATH=$tmp
autoload foobar
if	[[ $(foobar 2>/dev/null) != foo ]]
then	err_exit 'autoload not working'
fi
unset -f foobar
function foobar
{
	typeset -r x=3
	return 0
}
( foobar ) 2> /dev/null || err_exit "cannot unset readonly variable in function"
if	$SHELL -n 2> /dev/null <<-!
	abc()
	!
then	err_exit 'abc() without a function body is not a syntax error'
fi
function winpath
{
	usage='q pathname ...'
	typeset var format=s
	while   getopts  "$usage" var
	do      case $var in
		q)      format=q;;
	        esac
	done
	print done
}
if	[[ $( (winpath --man 2>/dev/null); print ok) != ok ]]
then	err_exit 'getopts --man in functions not working'
fi
if	[[ $( (winpath -z 2>/dev/null); print ok) != ok ]]
then	err_exit 'getopts with bad option in functions not working'
fi
unset -f x
function x
{
        print "$@"
}
typeset -ft x
if      [[ $(x x=y 2>/dev/null) != x=y ]]
then    err_exit 'name=value pair args not passed to traced functions'
fi
function bad
{
	false
}
trap 'val=false' ERR
val=true
bad
if	[[ $val != false ]]
then	err_exit 'set -e not working for functions'
fi
function bad
{
	false
	return 0
}
val=true
bad
if	[[ $val != true ]]
then	err_exit 'set -e not disabled for functions'
fi
bad()
{
	false
	return 0
}
val=true
bad
if	[[ $val != false ]]
then	err_exit 'set -e not inherited for POSIX functions'
fi
trap - ERR

function myexport
{
	nameref var=$1
	if	(( $# > 1 ))
	then	export	$1=$2
	fi
	if	(( $# > 2 ))
	then	print $(myexport "$1" "$3" )
		return
	fi
	typeset val
	val=$(export | grep "^$1=")
	print ${val#"$1="}
}
export dgk=base
val=$(myexport dgk fun)
if	[[ $val != fun ]]
then	err_exit "export inside function not working -- expected 'fun', got '$val'"
fi
val=$(export | sed -e '/^dgk=/!d' -e 's/^dgk=//')
if	[[ $val != base ]]
then	err_exit "export not restored after function call -- expected 'base', got '$val'"
fi
val=$(myexport dgk fun fun2)
if	[[ $val != fun2 ]]
then	err_exit "export inside function not working with recursive function -- expected 'fun2', got '$val'"
fi
val=$(export | sed -e '/^dgk=/!d' -e 's/^dgk=//')
if	[[ $val != base ]]
then	err_exit "export not restored after recursive function call -- expected 'base', got '$val'"
fi
val=$(dgk=try3 myexport dgk)
if	[[ $val != try3 ]]
then	err_exit "name=value not added to export list with function call -- expected 'try3', got '$val'"
fi
val=$(export | sed -e '/^dgk=/!d' -e 's/^dgk=//')
if	[[ $val != base ]]
then	err_exit "export not restored name=value function call -- expected 'base', got '$val'"
fi
unset zzz
val=$(myexport zzz fun)
if	[[ $val != fun ]]
then	err_exit "export inside function not working -- expected 'fun', got '$val'"
fi
val=$(export | sed -e '/^zzz=/!d' -e 's/^zzz=//')
if	[[ $val ]]
then	err_exit "unset variable exported after function call -- expected '', got '$val'"
fi

unset zzz
typeset -u zzz
function foo
{
	zzz=abc
	print $zzz
}
if	[[ $(foo)$(foo) != ABCABC ]]
then	err_exit 'attributes on unset variables not saved/restored'
fi
function xpd {
	typeset i j=$1
                for i
                        do print i=$i j=$j
                        [[ $i == a ]] && xpd b
                        done
                }
if	[[ $(xpd a c) != $'i=a j=a\ni=b j=b\ni=c j=a' ]]
then	err_exit 'for loop function optimization error'
fi

typeset -A visited
integer level=0
function closure
{
	(( $# > 5 )) && return 1
	((level < 2)) && ((level++))
	typeset tmp r=0
	visited[$1]=1

	for tmp in $level _$level
	do
		[[ ${visited[$tmp]} == 1 ]] && continue
		closure $tmp $* || r=1
	done
	return $r
}
closure 0 || err_exit 'for loop function optimization bug'
dir=$tmp/dir
mkdir $dir
cd $dir || { err_exit "cd $dir failed"; exit 1; }

(
	function a {
		print a
	}
	function b {
		print 1
		a
		print 2
	} > /dev/null
	typeset -ft a b
	PS4=X
	b 
) > file 2>&1
[[ $(<file) == *'Xprint 2'* ]] ||  err_exit 'function trace disabled by function call'
rm -f file

print 'false' > try
chmod +x try
cat > tst <<- EOF
	function ignore
	{
		./try
		return 0
	}
	trap "print error; exit 1" ERR
	ignore
EOF
if	[[ $($SHELL < tst)  == error ]]
then	err_exit 'ERR trap not cleared'
fi
FPATH=$dir
print ': This does nothing' > foobar
chmod +x foobar
unset -f foobar
{ foobar; } 2>/dev/null
got=$?
exp=126
if	[[ $got != $exp ]]
then	err_exit "function file without function definition processes wrong error -- expected '$exp', got '$got'"
fi
print 'set a b c' > dotscript
[[ $(PATH=$PATH: $SHELL -c '. dotscript;print $#') == 3 ]] || err_exit 'positional parameters not preserved with . script without arguments'
cd ~- || err_exit "cd back failed"
function errcheck
{
	trap 'print ERR; return 1' ERR
	false
	print ok
}
err=$(errcheck)
[[ $err == ERR ]] || err_exit 'trap on ERR not working in a function'
x="$(
	function foobar
	{
		print ok
	}
	typeset -f foobar
)"
eval "$x"  || err_exit 'typeset -f generates syntax error'
[[ $(foobar) != ok ]] && err_exit 'typeset -f not generating function'
unset -f a b c
a()
{
        b
        b
        print ${.sh.fun}
}
b() { : ;}
[[ $(a) == a ]] || err_exit '.sh.fun not set correctly in a function'
print $'a(){\ndate\n}'  | $SHELL 2> /dev/null || err_exit 'parser error in a(){;date;}'
cat > $tmp/data1 << '++EOF'
     1  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     2  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     3  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     4  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     5  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     6  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     7  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     8  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
     9  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    10  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    11  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    12  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    13  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    14  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    15  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    16  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    17  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    18  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    19  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    20  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
++EOF
cat > $tmp/script << '++EOF'
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

f()
{
cat <<\M
++EOF
cat $tmp/data1 >> $tmp/script
printf 'M\n}\n\nf\n\n' >> $tmp/script
$SHELL -c $tmp/script  > $tmp/data2
cmp -s $tmp/data[12] || err_exit 'error with long functions'
v=1
function f
{
	typeset i
	for i in 0 1
	do	typeset v
		v=$i
		[[ $v == $i ]] || return 1
	done
}
f || err_exit "typeset optimization bug"
function f
{
	print -r -- "$foo$bar"
}
function g
{
	print -r -- $(bar=bam f)
}
unset foo bar
[[ $(foo=hello g) == hellobam ]] || err_exit 'function exports not passed on'
[[ $(bar=hello g) == bam ]] || err_exit 'function exports not overridden'
unset -f foo
function foo
{
	typeset line=$1
	set +n
	while	[[ $line ]]
	do	if	[[ ! $varname ]]
		then	varname=${line%% *}
			line=${line##"$varname"?( )}
			[[ $line ]] && continue
		else	print ok
			return
		fi
		varname=
	done
}
[[ $(foo 'NUMBERED RECORDSIZE') == ok ]] || err_exit 'optimization error with undefined variable'
unset x
x=$(
	set -e
	integer count=0
	function err_f
	{
		if	((count++==3))
		then	print failed
		else	false
		fi
	}
	trap 'err_f' ERR
	false
)
[[ $x == failed ]] && err_exit 'ERR trap executed multiple times'
export environment
typeset global
function f
{
	typeset i t local

	for i
	do	case $i in
		[-+]*)	set "$@"
			continue
			;;
		local)	local=f
			t=$(typeset +f $local)
			;;
		global)	global=f
			t=$(typeset +f $global)
			;;
		environment)
			environment=f
			t=$(typeset +f $environment)
			;;
		literal)t=$(typeset +f f)
			;;
		positional)
			set -- f
			t=$(typeset +f $1)
			;;
		esac
		[[ $t ]] || err_exit "typeset +f \$$i failed"
	done
}
f local global environment literal positional
$SHELL -c '
	print exit 0 > '$tmp'/script
	chmod +x '$tmp'/script
	unset var
	var=( ident=1 )
	function fun
	{
		PATH='$tmp' script
	}
	fun
' || err_exit "compound variable cleanup before script exec failed"
( $SHELL << \++EOF++
function main
{
 	typeset key
 	typeset -A entry
 	entry[a]=( value=aaa )
}
main
++EOF++
) 2> /dev/null || err_exit 'function main fails'
optind=$OPTIND
sub()
{
        (
                OPTIND=1
                while getopts :abc OPTION "$@"
                do      print OPTIND=$OPTIND
                done
        )
}
[[ $(sub -a) == OPTIND=2 ]] || err_exit 'OPTIND should be 2'
[[ $(sub -a) == OPTIND=2 ]] || err_exit 'OPTIND should be 2 again'
[[ $OPTIND == "$optind" ]] || err_exit 'OPTIND should be 1'

function bar
{
	[[ -o nounset ]] && err_exit  'nounset option should not be inherited'
}
function foo
{
	set -o nounset
	bar
}
set +o nounset
foo
function red
{
	integer -S d=0
	printf 'red_one %d\n' d
	(( d++ ))
	return 0
}
[[ ${ red } != 'red_one 0' ]] && err_exit 'expected red_one 0'
[[ ${ red } != 'red_one 1' ]] && err_exit 'expected red_one 1'
xyz=$0
function traceback
{
	integer .level=.sh.level
	while((--.level>=0))
	do
		((.sh.level = .level))
		[[ $xyz == "$0" ]] || err_exit "\$xyz=$xyz does not match $0 on level ${.level}"
		[[ ${.sh.lineno} == "$1" ]] || err_exit "\${.sh.lineno}=${.sh.lineno} does not match $1 on level ${.level}"
	done
}

function foo
{
	typeset xyz=foo
	set -- $((LINENO+1))
	bar $LINENO "$1"
}

function bar
{
    	typeset xyz=bar
	set -- $((LINENO+2))
	trap 'traceback $LINENO' DEBUG
	: $LINENO "$1"
}

set -- $((LINENO+1))
foo $LINENO
function .sh.fun.set
{
	print -r -- "${.sh.value}"
}
function abc
{
	:
}
def()
{
	:
}
[[ $(abc) == abc ]] || err_exit '.sh.fun.set not capturing function name'
[[ $(def) == def ]] || err_exit '.sh.fun.set not capturing name()'
unset -f .sh.fun.set

# the traceback function above has set .sh.level in a loop; this should not break 'break'/'continue'
for i in 1
do	break
	err_exit "'break' broken after setting .sh.level in a loop"
done
for i in 1
do	continue
	err_exit "'continue' broken after setting .sh.level in a loop"
done

# tests for debug functions
basefile=${.sh.file}
integer baseline
cat > $tmp/debug << \+++
	: line 1

	: line 3
+++
# Print one line in a call stack
function _Dbg_print_frame
{
	typeset -i pos=$1
	typeset fn=$2
	typeset filename="$3"
	typeset -i line=$4
	typeset  arg=$5
	shift 5
	if	((pos==0))
	then	[[ $filename == "$basefile" ]] || err_exit "filename for level 0 is $filename not $basename"
		[[ $arg == DEBUG  ]] && ((baseline++))
		[[ $line == "$baseline" ]] || err_exit "line number for level 0 is $line not $baseline"
	elif	((pos==1))
	then	[[ $filename == "$tmp/debug" ]] ||  err_exit "filename for level 1 is $filename not $tmp/debug"
		[[ $* == 'foo bar' ]] || err_exit "args are '$*', not 'foo bar'"
		[[ $line == $arg ]] || err_exit "line number for level 1 is $line not $arg"
	else	err_exit "level should be 0 or 1 but is $pos"
	fi
}

function _Dbg_debug_trap_handler
{
	integer .level=.sh.level .max=.sh.level-1
	while((--.level>=0))
	do
		((.sh.level = .level))
      		_Dbg_print_frame  "${.level}" "$0" "${.sh.file}" "${.sh.lineno}" "${.sh.command##* }" "$@"
	done
}

((baseline=LINENO+2))
trap '_Dbg_debug_trap_handler' DEBUG
.  $tmp/debug foo bar
trap '' DEBUG

caller() {
  integer .level=.sh.level .max=.sh.level-1
  while((--.level>=0))
  do
      # as of 2022-07-12, .sh.level can only be changed inside a DEBUG trap;
      # the trap is executed right before turning it off with 'trap - DEBUG'
      trap '((.sh.level = .level)); print -r -- "${.sh.lineno}"' DEBUG
      trap - DEBUG
  done
}
bar() { caller;}
set -- $(bar)
[[ $1 == $2 ]] && err_exit ".sh.lineno optimization bug (got values: $*)"

( $SHELL  -c ' function foo { typeset x=$1;print $1;};z=();z=($(foo bar)) ') 2> /dev/null ||  err_exit 'using a function to set an array in a command sub fails'

{
got=$(
s=$(ulimit -s)
if	[[ $s == +([[:digit:]]) ]] && (( s < 32768 ))
then	# stack size doubled from 16384 to make this test pass under AddressSanitizer
	ulimit -s 32768 2>/dev/null
fi
$SHELL << \+++
f()
{
	if	(($1>1))
	then	x=$(f $(($1-1))) || exit 1
	fi
	return 0
}
f 257 && print ok
+++
)
} 2>/dev/null
[[ $got == ok ]] || err_exit 'cannot handle comsub depth > 256 in function'

tmp1=$tmp/job.1
tmp2=$tmp/job.2
cat > $tmp1 << +++
#! $SHELL
print \$\$
+++
chmod +x $tmp1
function foo
{
	typeset pid
	$tmp1 > $tmp2 & pid=$!
	wait $!
	got=$(< $tmp2)
	[[ $got == "$pid" ]] || err_exit 'wrong PID for & job in function' \
		"(expected $(printf %q "$pid"), got $(printf %q "$got"))"
}
foo
foo()
{
	$tmp1 > $tmp2 & pid=$!
	wait $!
	got=$(< $tmp2)
	[[ $got == "$pid" ]] || err_exit 'wrong PID for & job in POSIX function' \
		"(expected $(printf %q "$pid"), got $(printf %q "$got"))"
}
foo
unset pid
unset -f foo
# make sure compiled functions work
[[ $(tmp=$tmp $SHELL <<- \++++
	cat > $tmp/functions <<- \EOF
	 	function bar
	 	{
	 		print foo
	 	}
	 	function foobar
	 	{
	 		bar
	 	}
	EOF
	${SHCOMP:-${SHELL%/*}/shcomp} $tmp/functions > $tmp/foobar
	rm -f "$tmp/functions"
	chmod +x $tmp/foobar
	rm $tmp/!(dir|foobar)
	FPATH=$tmp
	PATH=$FPATH:$PATH
	foobar
++++
) == foo ]] > /dev/null  || err_exit 'functions compiled with shcomp not working'
# tests for compiled . scripts
print $'print hello\nprint world' > $tmp/foo
${SHCOMP:-${SHELL%/*}/shcomp} $tmp/foo > $tmp/foo.sh
val=$(. $tmp/foo.sh)
[[ $val ==  $'hello\nworld' ]] || err_exit "processing compiled dot files not working correctly val=$val"
# test for functions in shell having side effects.
unset -f foo foobar bar
cd "$tmp"
FPATH=$PWD
PATH=$FPATH:$PATH
cat > foo <<- \EOF
	function bar
	{
		print foobar
	}
	function foo
	{
		bar
	}
EOF
chmod +x foo
: $(foo)
[[ $(typeset +f) == *foo* ]] &&  err_exit 'function in subshell leaving side effect of function foo'
unset -f foo bar
:  $(foo)
[[ $(typeset +f) == *foo* ]] && err_exit 'function in subshell leaving side effects of function foo after reload'
[[ $(typeset +f) == *bar* ]] && err_exit 'function in subshell leaving side effects of function bar after reload'

unset -f foo
typeset -A bar
function foo
{
	typeset -i bar[$1].x
	bar[$1].x=5
}
foo sub
[[ ${!bar[@]} == sub ]] || err_exit 'scoping problem with compound array variables'

function A
{
        trap "> /dev/null;print TRAP A" EXIT
	# (( stderr )) && print >&2
}

function B
{
        trap "> /dev/null;print TRAP B" EXIT
        A
}
            
x=$(B)      
[[ $x == $'TRAP A\nTRAP B' ]] || err_exit "trap from functions in subshells fails got" $x

function foo
{
	typeset bar=abc
	unset bar
#	[[ $bar == bam ]] || err_exit 'unsetting local variable does not expose global variable'
	[[ $bar ]] && err_exit 'unsetting local variable exposes global variable'
}
bar=bam
foo

function gosleep
{
	"$bin_sleep" 1
}
x=$(
	ulimit -t unlimited 2>/dev/null 	# fork this subshell
	mysubpid=${.sh.pid}			# this subshell's new PID (new 93u+m feature)
	(
		sleep .25
		# kill 'gosleep' by getting the PIDs that have $mysubpid as their parent PID
		# (which includes this background process itself, but that's fine as we're invoking external 'kill')
		pids=$(UNIX95=1 ps -o ppid= -o pid= 2>/dev/null | awk -v p=$mysubpid '$1==p { print $2 }')
		[[ -n $pids ]] && "$bin_kill" $pids
	) &
	gosleep 2> /dev/null
	print ok
)
[[ $x == ok ]] || err_exit 'TERM signal sent to last process of function kills the script'

# verify that $0 does not change with functions defined as fun()
func1()
{
	[[ $0 == "$dol0" ]] || err_exit "\$0 changed in func1() to $0"
}
function func2
{
	[[ $0 == func2 ]] || err_exit "\$0 changed in func2() to $0"
	dol0=func2
	func1
}
func2

{ $SHELL <<- \EOF
	function foo
	{
	        typeset rc=0
		unset -f foo
		return $rc;
	}
	foo
EOF
} 2> /dev/null || err_exit  "problem with 'unset -f foo' within function foo"

val=$($SHELL 2> /dev/null <<- \EOF
	.sh.fun.set() { set -x; }
	function f1 { print -n ${.sh.fun}; set -o | grep xtrace;}
	function f2 { print -n ${.sh.fun}; set -o | grep xtrace;}
	f1
	set -o | grep xtrace
	f2
EOF)
[[ $val == f1xtrace*on*off*f2xtrace*on* ]] || err_exit "'.sh.fun.set() { set -x; }' not tracing all functions"

function foo
{
	typeset opt OPTIND=1 OPTARG hflag=
	while getopts hi: opt
	do	case $opt in
		h)	hflag=1;;
	        i)	[[ $OPTARG == foobar ]] || err_exit 'OPTARG should be set to foobar in function foo';;
		esac
	done
	shift $((OPTIND - 1))
	(( OPTIND == 4 )) || err_exit "OPTIND is $OPTIND at end of function foo; it should be 4"  
	[[ $1 == foo2 ]] || err_exit "\$1 is $1, not foo after getopts in function"
}
OPTIND=6 OPTARG=xxx
foo -h -i foobar foo2
[[ $OPTARG == xxx ]] || err_exit 'getopts in function changes global OPTARG'
(( OPTIND == 6 )) || err_exit 'getopts in function changes global OPTIND'

if	[[ ! $compiled ]]
then	function foo { getopts --man; }
	[[ $(typeset -f foo) == 'function foo { getopts --man; }' ]] || err_exit 'typeset -f not work for function with getopts'
fi

function foo
{
	let 1
	return $1
}
# As of ksh 93u+m 2021-12-08, you can use arbitrary signed integer return values in the current (sub)shell.
vals=(135 255 256 267 -1 1234 -4567)
for ((i=0; i < ${#vals[@]}; i++))
do	foo ${vals[i]}
	[[ $? == "${vals[i]}" ]] || err_exit "function exit ${vals[i]} should set \$? to ${vals[i]}"
done

function foo
{
	typeset pid
	sleep 2 & pid=$!
	sleep 1
	kill -TERM $pid
	wait $pid
	rc=$?
	return $rc
}
foo  2> /dev/null
rc=$?
exp=$((256+$(kill -l TERM) ))
[[  $rc == "$exp" ]] || err_exit "expected exitval $exp got $rc"

# ======
# Verify that directories in the path search list which should be skipped
# (e.g. because they don't exist) interact correctly with autoloaded functions.
# See https://github.com/att/ast/issues/1454
expect="Func cd called with |$tmp/usr|
$tmp/usr"
actual=$(
	set -- wrong args passed
	mkdir -p "$tmp/usr/bin"
	print 'echo "wrong file executed ($*)"' >"$tmp/usr/bin/cd"
	prefix=$tmp/ksh.$$

	FPATH=$prefix/bad:$prefix/functions
	mkdir -p "$prefix/functions"
	print 'function cd { echo "Func cd called with |$*|"; command cd "$@"; }' >"$prefix/functions/cd"
	typeset -fu cd

	PATH=$tmp/arglebargle:$tmp/usr/bin:$tmp/bin
	cd "$tmp/usr"
	pwd
)
actual_status=$?
expect_status=0
[[ $actual_status == "$expect_status" ]] ||
    err_exit "autoload function skipped dir test wrong status (expected $expect_status, got $actual_status)"
[[ $actual == "$expect" ]] ||
    err_exit "autoload function skipped dir test wrong output (expected $(printf %q "$expect"), got $(printf %q "$actual"))"

# ======
# When a function unsets itself, it should not fail to be unset
# https://github.com/ksh93/ksh/issues/21
got=$( { "$SHELL" -c 'PATH=/dev/null; fn() { unset -f fn; true; }; fn'; } 2>&1 )
(( (e=$?)==0 )) || err_exit 'unset of POSIX function in the calling stack fails' "(got status $e, $(printf %q "$got"))"
got=$( { "$SHELL" -c 'PATH=/dev/null; function ftest { ftest2; }; function ftest2 { unset -f ftest; }; ftest'; } 2>&1 )
(( (e=$?)==0 )) || err_exit 'unset of ksh function in the calling stack fails' "(got status $e, $(printf %q "$got"))"
got=$( { "$SHELL" -c 'PATH=/dev/null; fn() { unset -f fn; true; }; fn; fn'; } 2>&1 )
(( (e=$?)==127 )) ||  err_exit 'unset of POSIX function fails when it is still running' "(got status $e, $(printf %q "$got"))"
got=$( { "$SHELL" -c 'PATH=/dev/null; function fn { unset -f fn; true; }; fn; fn'; } 2>&1 )
(( (e=$?)==127 )) || err_exit 'unset of ksh function fails when it is still running' "(got status $e, $(printf %q "$got"))"

# ======
# Check if environment variables passed while invoking a function are exported
# https://github.com/att/ast/issues/32
# https://github.com/ksh93/ksh/issues/465
exp='typeset -x -F 5 num=7.75000'
exp=$exp$'\n'$exp$'\n'$exp
got=$(
	function f1 { typeset -p num; f2; }
	function f2 { typeset -p num; f3; }
	function f3 { typeset -p num; }
	typeset -F5 num
	num=3.25+4.5 f1
)
[[ $got == "$exp" ]] || err_exit 'assignment preceding ksh function call is not correctly exported or propagated' \
	"(expected $(printf %q "$exp"), got $(printf %q "$got"))"

exp='typeset -F 5 num=7.75000'
exp=$exp$'\n'$exp$'\n'$exp
got=$(
	f1() { typeset -p num; f2; }
	f2() { typeset -p num; }
	typeset -F5 num
	num=3.25+4.5 f1
	typeset -p num
)
[[ $got == "$exp" ]] || err_exit 'assignment preceding POSIX function call is not correctly exported or propagated' \
	"(expected $(printf %q "$exp"), got $(printf %q "$got"))"

# ======
# Over-shifting in a POSIX function should terminate the script
$SHELL <<- \EOF
	fun() {
		shift 10
	}
	for i in a b
	do
		fun 2> /dev/null
		[[ $i == b ]] && exit 2
	done
EOF
[[ $? == 2 ]] && err_exit 'Over-shifting in a POSIX function does not terminate the script if the function call has a redirection'

# ======
# https://bugzilla.redhat.com/1116508
expect=$'13/37/1/1'
actual=$(
	foo() {
		print foo | read
		return 13
	}
	out=$(foo)
	print -n $?/
	foo() {
		print foo | read
		ls /dev/null
		return 37
	}
	out=$(foo)
	print -n $?/
	foo() {
		print foo | ! read
	}
	out=$(foo)
	print -n $?/
	foo() {
		! true
	}
	out=$(foo)
	print -n $?
)
[[ $actual == "$expect" ]] || err_exit "wrong exit status from function invoked by command substitution" \
	"(expected $(printf %q "$expect"), got $(printf %q "$actual"))"

# ======
# https://bugzilla.redhat.com/1117404

cat >$tmp/crash_rhbz1117404.ksh <<-'EOF'
	trap "" HUP			# trigger part 1: signal ignored in main shell
	function ksh_fun
	{
		trap ": foo" HUP	# trigger part 2: any local trap (empty or not) on same signal in ksh function
	}
	for((i=0; i<2500; i++))
	do	ksh_fun
	done
EOF
got=$( { "$SHELL" "$tmp/crash_rhbz1117404.ksh"; } 2>&1)
((!(e = $?))) || err_exit 'crash while handling function-local trap' \
	"(got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"), $(printf %q "$got"))"

# ======
# 'typeset -g' should cause the active function scope to be ignored.
# https://github.com/ksh93/ksh/issues/479#issuecomment-1140523291
if	! command typeset -g x 2>/dev/null
then
	warning "shell does not have 'typeset -g'; skipping those tests"
else
	unset x arr a b c
	# must specify the length for -X as the default is -X 24 on 32-bit systems and -X 32 on 64-bit systems
	typeset -A exp=(
		['x=123; function f { typeset -g x=456; }; function g { typeset x=789; f; }; g; typeset -p x']='x=456'
		['x=123; function f { typeset -g -i x; }; f; typeset -p x']='typeset -i x=123'
		['x=123; function f { typeset -g -F x; }; f; typeset -p x']='typeset -F x=123.0000000000'
		['x=123; function f { typeset -g -E x; }; f; typeset -p x']='typeset -E x=123'
		['x=123; function f { typeset -g -X24 x; }; f; typeset -p x']='typeset -X 24 x=0x1.ec0000000000000000000000p+6'
		['x=aBc; function f { typeset -g -u x; }; f; typeset -p x']='typeset -u x=ABC'
		['x=aBc; function f { typeset -g -l x; }; f; typeset -p x']='typeset -l x=abc'
		['x=aBc; function f { typeset -g -L x; }; f; typeset -p x']='typeset -L 3 x=aBc'
		['x=aBc; function f { typeset -g -R x; }; f; typeset -p x']='typeset -R 3 x=aBc'
		['x=aBc; function f { typeset -g -Z x; }; f; typeset -p x']='typeset -Z 3 -R 3 x=aBc'
		['x=aBc; function f { typeset -g -L2 x; }; f; typeset -p x']='typeset -L 2 x=aB'
		['x=aBc; function f { typeset -g -R2 x; }; f; typeset -p x']='typeset -R 2 x=Bc'
		['x=aBc; function f { typeset -g -Z2 x; }; f; typeset -p x']='typeset -Z 2 -R 2 x=Bc'
		['x=8; function f { typeset -g -i2 x; }; f; typeset -p x']='typeset -i 2 x=2#1000'
		['x=8; function f { typeset -g -i8 x; }; f; typeset -p x']='typeset -i 8 x=8#10'
		['arr=(a b c); function f { typeset -g -i arr[1]=(1 2 3); }; f; typeset -p arr']='typeset -a -i arr=(0 (1 2 3) 0)'
		['arr=(a b c); function f { typeset -g -F arr[1]=(1 2 3); }; f; typeset -p arr']='typeset -a -F arr=(0.0000000000 (1.0000000000 2.0000000000 3.0000000000) 0.0000000000)'
		['arr=(a b c); function f { typeset -g -E arr[1]=(1 2 3); }; f; typeset -p arr']='typeset -a -E arr=(0 (1 2 3) 0)'
		['arr=(a b c); function f { typeset -g -X24 arr[1]=(1 2 3); }; f; typeset -p arr']='typeset -a -X 24 arr=(0x0.000000000000000000000000p+0 (0x1.000000000000000000000000p+0 0x1.000000000000000000000000p+1 0x1.800000000000000000000000p+1) 0x0.000000000000000000000000p+0)'
	)
	for cmd in "${!exp[@]}"
	do
		got=$(set +x; eval "$cmd" 2>&1)
		[[ $got == "${exp[$cmd]}" ]] || err_exit "typeset -g in $(printf %q "$cmd") failed to activate global" \
			"scope from ksh function (expected $(printf %q "${exp[$cmd]}"), got $(printf %q "$got"))"
	done
	unset exp
fi

# ======
# funcname.ksh crashed
# https://github.com/ksh93/ksh/issues/212
cat >$tmp/funcname.ksh <<'EOF'
# tweaked version of funname.ksh by Daniel Douglas
# https://gist.github.com/ormaaj/12874b68acd06ee98b59
# Used by permission: "Consider all my gists MIT / do whatever."
# https://github.com/ksh93/ksh/issues/212#issuecomment-807915937

# run in subshell for additional regression testing
(
	IFS='-'  # element separator for "$*" etc., incl. "${FUNCNAME[*]}"
	typeset -a FUNCNAME

	function FUNCNAME.get {
	    nameref self=${.sh.name}
	    if (( .sh.subscript < .sh.level )); then
		trap "(( .sh.level -= .sh.subscript + 1 )); eval '(( .sh.level = ${.sh.level} ))' \; _=\${.sh.fun}" DEBUG
		trap - DEBUG;
	    fi

	    (( .sh.subscript < .sh.level - 2 )) && self[.sh.subscript + 1]=
	}

	function f {
	    if (($1 < 10)); then
		print -r -- "${FUNCNAME[*]}"
		g $(($1 + 1))
	    fi
	    print -r -- "${FUNCNAME[*]}"
	}

	function g {
	    if (($1 < 10)); then
		print -r -- "${FUNCNAME[*]}"
		f $(($1 + 1))
	    fi
	    print -r -- "${FUNCNAME[*]}"
	}

	#typeset -ft FUNCNAME.get f g
	f 0
)
: do not optimize out the subshell
EOF
exp='f
g-f
f-g-f
g-f-g-f
f-g-f-g-f
g-f-g-f-g-f
f-g-f-g-f-g-f
g-f-g-f-g-f-g-f
f-g-f-g-f-g-f-g-f
g-f-g-f-g-f-g-f-g-f
f-g-f-g-f-g-f-g-f-g-f
g-f-g-f-g-f-g-f-g-f-
f-g-f-g-f-g-f-g-f--
g-f-g-f-g-f-g-f---
f-g-f-g-f-g-f----
g-f-g-f-g-f-----
f-g-f-g-f------
g-f-g-f-------
f-g-f--------
g-f---------
f----------'
got=$(set +x; { "$SHELL" funcname.ksh ;} 2>&1)
[[ $got == "$exp" ]] || err_exit 'funcname.ksh crash (direct run)' \
	"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# dotting it slightly changes the output
exp='f-
g-f-
f-g-f-
g-f-g-f-
f-g-f-g-f-
g-f-g-f-g-f-
f-g-f-g-f-g-f-
g-f-g-f-g-f-g-f-
f-g-f-g-f-g-f-g-f-
g-f-g-f-g-f-g-f-g-f-
f-g-f-g-f-g-f-g-f-g-f-
g-f-g-f-g-f-g-f-g-f--
f-g-f-g-f-g-f-g-f---
g-f-g-f-g-f-g-f----
f-g-f-g-f-g-f-----
g-f-g-f-g-f------
f-g-f-g-f-------
g-f-g-f--------
f-g-f---------
g-f----------
f-----------'
got=$(set +x; { "$SHELL" -c '. ./funcname.ksh' ;} 2>&1)
[[ $got == "$exp" ]] || err_exit 'funcname.ksh crash (dot)' \
	"(expected $(printf %q "$exp"), got $(printf %q "$got"))"

# ======
# in 'funcname() simple_command' definitions, the first command word was sometimes corrupted with trailing garbage
# https://github.com/ksh93/ksh/issues/203
# (do not change this test; even indenting may cause the bug to fail to be triggered)
m="command word corruption in 'fun() simple_command'"
v2=:
f() "$v2" hello
f || err_exit "$m"
v23=:
f() "$v23" hello
f || err_exit "$m"
v234=:
f() "$v234" hello
f || err_exit "$m"
v2345=:
f() "$v2345" hello
f || err_exit "$m"
v23456=:
f() "$v23456" hello
f || err_exit "$m"
v234567=:
f() "$v234567" hello
f || err_exit "$m"
v2345678=:
f() "$v2345678" hello
f || err_exit "$m"
v23456789=:
f() "$v23456789" hello
f || err_exit "$m"
v234567890=:
f() "$v234567890" hello
f || err_exit "$m"
unset -f f
unset -v "${!v2@}"

# ======
# Test 'unset -f' in subshell
# https://github.com/ksh93/ksh/issues/646
# NOTE: for ast commands, '--version' is expected to exit with status 2
exp='^  version         [[:alpha:]]{2,} (.*) ....-..-..$'
for b in cd disown fg getopts printf pwd read ulimit umask whence
do	got=$(unset -f "$b"; PATH=/dev/null; "$b" --version 2>&1)
	[[ e=$? -eq 2 && $got =~ $exp ]] || err_exit "'unset -f $b' fails in subshell (1a)" \
		"(expected status 2 and ERE match of $(printf %q "$exp"), got status $e and $(printf %q "$got"))"

	# the extra 'exit' is needed to avoid optimising out the subshell
	got=$("$SHELL" -c "(unset -f $b; PATH=/dev/null; $b --version); exit" 2>&1)
	[[ e=$? -eq 2 && $got =~ $exp ]] || err_exit "'unset -f $b' fails in subshell (1b)" \
		"(expected status 2 and ERE match of $(printf %q "$exp"), got status $e and $(printf %q "$got"))"

	eval "$b() { echo BAD; }"
	got=$(unset -f "$b"; PATH=/dev/null; "$b" --version 2>&1)
	[[ e=$? -eq 2 && $got =~ $exp ]] || err_exit "'unset -f $b' fails in subshell (2a)" \
		"(expected status 2 and ERE match of $(printf %q "$exp"), got status $e and $(printf %q "$got"))"
	unset -f "$b"

	got=$("$SHELL" -c "$b() { :; }; (unset -f $b; PATH=/dev/null; $b --version); exit" 2>&1)
	[[ e=$? -eq 2 && $got =~ $exp ]] || err_exit "'unset -f $b' fails in subshell (2b)" \
		"(expected status 2 and ERE match of $(printf %q "$exp"), got status $e and $(printf %q "$got"))"
done

# ======
exit $((Errors<125?Errors:125))
