########################################################################
#                                                                      #
#               This software is part of the ast package               #
#          Copyright (c) 1982-2014 AT&T Intellectual Property          #
#                      and is licensed under the                       #
#                 Eclipse Public License, Version 1.0                  #
#                    by AT&T Intellectual Property                     #
#                                                                      #
#                A copy of the License is available at                 #
#          http://www.eclipse.org/org/documents/epl-v10.html           #
#         (with md5 checksum b35adb5213ca9657e911e9befb180842)         #
#                                                                      #
#              Information and Software Systems Research               #
#                            AT&T Research                             #
#                           Florham Park NJ                            #
#                                                                      #
#                    David Korn <dgkorn@gmail.com>                     #
#                                                                      #
########################################################################

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

integer foo=33
bar=bye
# Check for global variables and $0
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
    log_error "command print not working inside print function"
fi

unset -f print

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

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

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

if [[ $bar == foo ]]
then
    log_error 'scoping error'
fi

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

foobar 4
if [[ $foo != 36 ]]
then
    log_error EXIT trap in wrong scope
fi

unset -f foobar || log_error "cannot unset function foobar"
typeset -f foobar>/dev/null  && log_error "typeset -f has incorrect exit status"

function foobar
{
    (return 0)
}
> $TEST_DIR/test1
{
foobar
if [[ -r $TEST_DIR/test1 ]]
then
    rm -r $TEST_DIR/test1
else
    log_error 'return within subshell inside function error'
fi

}
abc() print hi
if [[ $(abc) != hi ]]
then
    log_error 'abc() print hi not working'
fi

( unset -f abc )
if [[ $(abc 2>/dev/null) != hi ]]
then
    log_error 'abc() print hi not working after subshell unset'
fi

(
    function f
    {
        exit 1
    }
    f
    log_error 'exit from function not working'
)
unset -f foo
function foo
{
    x=2
    (
        x=3
        cd $TEST_DIR
        print bar
    )
    if [[ $x != 2 ]]
    then
    log_error 'value of x not restored after subshell inside function'
    fi

}
x=1
if [[ $(foo) != bar ]]
then
    log_error 'cd inside nested subshell not working'
fi

if [[ $PWD != "$TEST_DIR" ]]
then
    log_error 'cd inside nested subshell changes $PWD'
fi

fun() /bin/echo hello
if [[ $(fun) != hello ]]
then
    log_error one line functions not working
fi

cat > $TEST_DIR/script <<-\!
	print -r -- "$1"
!
chmod +x $TEST_DIR/script
function passargs
{
    $TEST_DIR/script "$@"
}
if [[ $(passargs one) != one ]]
then
    log_error 'passing args from functions to scripts not working'
fi

cat > $TEST_DIR/script <<-\!
	trap 'exit 0' EXIT
	function foo
	{
    		/tmp > /dev/null 2>&1
	}
	foo
!

if ! $TEST_DIR/script
then
    log_error 'exit trap incorrectly triggered'
fi

if ! $SHELL -c $TEST_DIR/script
then
    log_error 'exit trap incorrectly triggered when invoked with -c'
fi

$SHELL -c "trap 'rm $TEST_DIR/script' EXIT"
if [[ -f $TEST_DIR/script ]]
then
    log_error 'exit trap not triggered when invoked with -c'
fi

cat > $TEST_DIR/script <<- \EOF
	foobar()
	{
		return
	}
	shift
	foobar
	print -r -- "$1"
EOF
chmod +x $TEST_DIR/script
if [[ $( $SHELL $TEST_DIR/script arg1 arg2) != arg2 ]]
then
    log_error 'arguments not restored by posix functions'
fi

function foo
{
    print hello
}
(
    function foo
    {
        print bar
    }
    if [[ $(foo) != bar ]]
    then
        log_error 'function definitions inside subshells not working'
    fi
)

if [[ $(foo) != hello ]]
then
    log_error '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
    log_error 'variable assignment list not using parent scope'
fi

unset -f foobar
cat > $TEST_DIR/foobar <<!
function foobar
{
    print foo
}
!
chmod +x $TEST_DIR/foobar
FPATH=$TEST_DIR
print 'function zzz { return 7; }' > zzz
PATH="$SAFE_PATH"
zzz
[[ $? == 7 ]] || log_error 'function not found in . when $PWD is in FPATH'
PATH="$FULL_PATH"
autoload foobar
expect=foo
actual="$(foobar)"
[[ $actual == $expect ]] || log_error 'autoload not working' "$expect" "$actual"

unset -f foobar
function foobar
{
    typeset -r x=3
    return 0
}
( foobar ) 2> /dev/null || log_error "cannot unset readonly variable in function"
if $SHELL -n 2> /dev/null <<-!
	abc()
	!
then
    log_error '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
    log_error 'getopts --man in functions not working'
fi

if [[ $( (winpath -z 2>/dev/null); print ok) != ok ]]
then
    log_error '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
    log_error 'name=value pair args not passed to traced functions'
fi

function bad
{
    false
}
trap 'val=false' ERR
val=true
bad
if [[ $val != false ]]
then
    log_error 'set -e not working for functions'
fi

function bad
{
    false
    return 0
}
val=true
bad
if [[ $val != true ]]
then
    log_error 'set -e not disabled for functions'
fi

bad()
{
    false
    return 0
}
val=true
bad
if [[ $val != false ]]
then
    log_error '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
    log_error "export inside function not working -- expected 'fun', got '$val'"
fi

val=$(export | sed -e '/^dgk=/!d' -e 's/^dgk=//')
if [[ $val != base ]]
then
    log_error "export not restored after function call -- expected 'base', got '$val'"
fi

val=$(myexport dgk fun fun2)
if [[ $val != fun2 ]]
then
    log_error "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
    log_error "export not restored after recursive function call -- expected 'base', got '$val'"
fi

val=$(dgk=try3 myexport dgk)
if [[ $val != try3 ]]
then
    log_error "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
    log_error "export not restored name=value function call -- expected 'base', got '$val'"
fi

unset zzz
val=$(myexport zzz fun)
if [[ $val != fun ]]
then
    log_error "export inside function not working -- expected 'fun', got '$val'"
fi

val=$(export | sed -e '/^zzz=/!d' -e 's/^zzz=//')
if [[ $val ]]
then
    log_error "unset varaible exported after function call -- expected '', got '$val'"
fi

unset zzz
typeset -u zzz
function foo
{
    zzz=abc
    print $zzz
}

if [[ $(foo)$(foo) != ABCABC ]]
then
    log_error '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
    log_error '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[$TEST_DIR]} == 1 ]] && continue
        closure $TEST_DIR $* || r=1
    done
    return $r
}
closure 0 || log_error -u2 'for loop function optimization bug2'
dir=$TEST_DIR/dir
mkdir $dir
cd $dir || { log_error "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'* ]] ||  log_error '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
    log_error 'ERR trap not cleared'
fi
cd $TEST_DIR

FPATH=$TEST_DIR
print ': This does nothing' > foobar
chmod +x foobar
unset -f foobar
( foobar; )
got=$?
exp=126
[[ $got == $exp ]] ||
    log_error "function file without function definition processes wrong error" "$exp" "$got"

print 'set a b c' > dotscript
[[ $(PATH=$PATH: $SHELL -c '. dotscript; print $#') == 3 ]] ||
    log_error 'positional parameters not preserved with . script without arguments'
function errcheck
{
    trap 'print ERR; return 1' ERR
    false
    print ok
}
err=$(errcheck)
[[ $err == ERR ]] || log_error 'trap on ERR not working in a function'
x="$(
    function foobar
    {
        print ok
    }
    typeset -f foobar
)"
eval "$x"  || log_error 'typeset -f generates syntax error'
[[ $(foobar) != ok ]] && log_error 'typeset -f not generating function'
unset -f a b c
a()
{
        b
        b
        print ${.sh.fun}
}
b() { : ;}
[[ $(a) == a ]] || log_error '.sh.fun not set correctly in a function'
print $'a(){\ndate\n}'  | $SHELL 2> /dev/null || log_error 'parser error in a(){;date;}'
cat > $TEST_DIR/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 > $TEST_DIR/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 $TEST_DIR/data1 >> $TEST_DIR/script
printf 'M\n}\n\nf\n\n' >> $TEST_DIR/script
$SHELL -c $TEST_DIR/script  > $TEST_DIR/data2
cmp -s $TEST_DIR/data[12] || log_error '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 || log_error "typeset optimization bug"
function f
{
    print -r -- "$foo$bar"
}
function g
{
    print -r -- $(bar=bam f)
}
unset foo bar
[[ $(foo=hello g) == hellobam ]] || log_error 'function exports not passed on'
[[ $(bar=hello g) == bam ]] || log_error '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 ]] || log_error '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 ]] && log_error '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 ]] || log_error "typeset +f \$$i failed"
    done
}
f local global environment literal positional
$SHELL -c '
    print exit 0 > '$TEST_DIR'/script
    chmod +x '$TEST_DIR'/script
    unset var
    var=( ident=1 )
    function fun
    {
        PATH='$TEST_DIR' script
    }
    fun
' || log_error "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 || log_error 'function main fails'
optind=$OPTIND
sub()
{
        (
                OPTIND=1
                while getopts :abc OPTION "$@"
                do      print OPTIND=$OPTIND
                done
        )
}
expect="OPTIND=2"
actual=$(sub -a)
[[ $actual == $expect ]] || log_error 'OPTIND should be 2' "$expect" "$actual"
actual=$(sub -a)
[[ $actual == $expect ]] || log_error 'OPTIND should be 2 again' "$expect" "$actual"
expect=$optind
actual=$OPTIND
[[ $actual == $expect ]] || log_error 'OPTIND is wrong' "$expect" "$actual"

function bar
{
    [[ -o nounset ]] && log_error  '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' ]] && log_error 'expected red_one 0'
[[ ${ red } != 'red_one 1' ]] && log_error 'expected red_one 1'

xyz=$0
function tb2
{
    integer .level=.sh.level
    while((--.level>=0))
    do
        ((.sh.level = .level))
        [[ $xyz == "$0" ]] || log_error "\$xyz=$xyz does not match $0 on level ${.level}"
        [[ ${.sh.lineno} == "$1" ]] || log_error "\${.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 'tb2 $LINENO' DEBUG
    : $LINENO "$1"
}

set -- $((LINENO+1))
log_info 'TODO: Enable this test once we understand why this trivial change breaks it.'
# foo $LINENO

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

# tests for debug functions
basefile=${.sh.file}
integer baseline
cat > $TEST_DIR/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" ]] || log_error "filename for level 0 is $filename not $basename"
        [[ $arg == DEBUG  ]] && ((baseline++))
        [[ $line == "$baseline" ]] || log_error "line number for level 0 is $line not $baseline"
    elif ((pos==1))
    then
    [[ $filename == "$TEST_DIR/debug" ]] ||  log_error "filename for level 1 is $filename not $TEST_DIR/debug"
        [[ $* == 'foo bar' ]] || log_error "args are '$*', not 'foo bar'"
        [[ $line == $arg ]] || log_error "line number for level 1 is $line not $arg"
    else    log_error "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
.  $TEST_DIR/debug foo bar
trap '' DEBUG

caller() {
  integer .level=.sh.level .max=.sh.level-1
  while((--.level>=0))
  do
      ((.sh.level = .level))
      print -r -- "${.sh.lineno}"
  done
}
bar() { caller;}
set -- $(bar)
[[ $1 == $2 ]] && log_error ".sh.inline optimization bug"
( $SHELL  -c ' function foo { typeset x=$1;print $1;};z=();z=($(foo bar)) ') 2> /dev/null ||  log_error 'using a function to set an array in a command sub  fails'

# Note: When run under ASAN the stack needs to be larger than 16384KB. Setting it to 32768 works
# for me on macOS. Otherwise it fails when the stack overflows.
if [[ $OS_NAME == cygwin* ]]
then
    # At the moment this causes the subshell to die with a memory fault (presumably a SIGSEGV but
    # that is unclear).
    log_warning 'TODO: enable this test on Cygwin'
else
actual=$( $SHELL << \+++
f()
{
    if (($1>1))
    then
    x=$(f $(($1-1))) || exit 1
    fi

    return 0
}
f 257 && print ok || print fail
+++
)
expect=ok
[[ $actual == $expect ]] || log_error 'comsub depth > 256 in function failed' "$expect" "$actual"
fi

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

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

# ========
function gosleep {
    $bin_sleep 1
}
actual=$(
    (sleep 0.5; ps | grep '[s]leep 1' | read pid extra; [[ $pid ]] && kill -- $pid) &
    gosleep 2> /dev/null
    print ok
)
expect=ok
[[ $actual == $expect ]] ||
    log_error 'TERM signal sent to last process of function kills the script' "$expect" "$actual"

# ========
# Verify that $0 does not change with functions defined as fun().
func1()
{
    [[ $0 == "$dol0" ]] || log_error "\$0 changed in func1() to $0"
}
function func2
{
    [[ $0 == func2 ]] || log_error "\$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 || log_error  '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* ]] || log_error "'.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 ]] || log_error 'OPTARG should be set to foobar in function foo';;
        esac
    done
    shift $((OPTIND - 1))
    (( OPTIND == 4 )) || log_error "OPTIND is $OPTIND at end of function foo; it should be 4"
    [[ $1 == foo2 ]] || log_error "\$1 is $1, not foo after getopts in function"
}
OPTIND=6 OPTARG=xxx
foo -h -i foobar foo2
[[ $OPTARG == xxx ]] || log_error 'getopts in function changes global OPTARG'
(( OPTIND == 6 )) || log_error 'getopts in function changes global OPTIND'

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


function foo
{
    let 1
    return $1
}
invals=(135 255 256 267 -1)
outvals=(135 255 0 267 255)
for ((i=0; i < ${#invals[@]}; i++))
do    foo ${invals[i]}
    [[ $? == "${outvals[i]}" ]] || log_error "function exit ${invals[i]} should set \$? to ${outvals[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" ]] || log_error "expected exitval $exp got $rc"

$SHELL  <<- \EOF
	fun() { shift 10 ;}
	for i in a b
	do    fun 2> /dev/null
		[[ $i == b ]] && log_error 'The bad shift did not terminated the loop'
	done
EOF

$SHELL 2> /dev/null -uc 'typeset -T My_t=( float x);My_t -a A=( (x=1) )
foo()
{
    ((  (A[i-1].x != A[i].x) ))
}' || log_error 'unset parameter in function not called causes error with set -u'

$SHELL -c 'function ftest { ftest2; }; function ftest2 { unset -f ftest; }; ftest' 2> /dev/null || log_error 'unset of function in the calling stack fails'

# Check if environment variables passed while invoking a function are exported
# https://github.com/att/ast/issues/32
function f2 { env | grep -q "^foo" || log_error "Environment variable is not propogated from caller function"; }
function f1 { f2; env | grep -q "^foo" || log_error "Environment variable is not passed to a function"; }
foo=bar f1
