xref: /titanic_41/usr/src/lib/libshell/common/tests/vartree2.sh (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
17c2fbfb3SApril Chin########################################################################
27c2fbfb3SApril Chin#                                                                      #
37c2fbfb3SApril Chin#               This software is part of the ast package               #
4*3e14f97fSRoger A. Faulkner#          Copyright (c) 1982-2010 AT&T Intellectual Property          #
57c2fbfb3SApril Chin#                      and is licensed under the                       #
67c2fbfb3SApril Chin#                  Common Public License, Version 1.0                  #
77c2fbfb3SApril Chin#                    by AT&T Intellectual Property                     #
87c2fbfb3SApril Chin#                                                                      #
97c2fbfb3SApril Chin#                A copy of the License is available at                 #
107c2fbfb3SApril Chin#            http://www.opensource.org/licenses/cpl1.0.txt             #
117c2fbfb3SApril Chin#         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         #
127c2fbfb3SApril Chin#                                                                      #
137c2fbfb3SApril Chin#              Information and Software Systems Research               #
147c2fbfb3SApril Chin#                            AT&T Research                             #
157c2fbfb3SApril Chin#                           Florham Park NJ                            #
167c2fbfb3SApril Chin#                                                                      #
177c2fbfb3SApril Chin#                  David Korn <dgk@research.att.com>                   #
187c2fbfb3SApril Chin#                                                                      #
197c2fbfb3SApril Chin########################################################################
207c2fbfb3SApril Chin#
217c2fbfb3SApril Chin# variable tree test #002
227c2fbfb3SApril Chin# Propose of this test is whether ksh93 handles global variable trees
237c2fbfb3SApril Chin# and function-local variable trees the same way, including "nameref"
247c2fbfb3SApril Chin# and "unset" handling.
257c2fbfb3SApril Chin#
267c2fbfb3SApril Chin
277c2fbfb3SApril Chinfunction err_exit
287c2fbfb3SApril Chin{
297c2fbfb3SApril Chin	print -u2 -n "\t"
307c2fbfb3SApril Chin	print -u2 -r ${Command}[$1]: "${@:2}"
317c2fbfb3SApril Chin	(( Errors+=1 ))
327c2fbfb3SApril Chin}
337c2fbfb3SApril Chin
347c2fbfb3SApril Chinalias err_exit='err_exit $LINENO'
357c2fbfb3SApril Chin
367c2fbfb3SApril Chin# "built_tree1" and "built_tree2" are identical except the way how they test
377c2fbfb3SApril Chin# whether a variable exists:
387c2fbfb3SApril Chin# - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable
397c2fbfb3SApril Chin#    as non-zero length content
407c2fbfb3SApril Chin# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell
417c2fbfb3SApril Chinfunction build_tree1
427c2fbfb3SApril Chin{
437c2fbfb3SApril Chin#set -o errexit -o xtrace
447c2fbfb3SApril Chin	typeset index
457c2fbfb3SApril Chin	typeset s
467c2fbfb3SApril Chin	typeset i
477c2fbfb3SApril Chin	typeset dummy
487c2fbfb3SApril Chin	typeset a b c d e f
497c2fbfb3SApril Chin
507c2fbfb3SApril Chin	nameref dest_tree="$1" # destination tree
517c2fbfb3SApril Chin	nameref srcdata="$2"   # source data
527c2fbfb3SApril Chin	typeset tree_mode="$3" # mode to define the type of leads
537c2fbfb3SApril Chin
547c2fbfb3SApril Chin	typeset -A dest_tree.l1
557c2fbfb3SApril Chin
567c2fbfb3SApril Chin	for index in "${!srcdata.hashnodes[@]}" ; do
577c2fbfb3SApril Chin		nameref node=srcdata.hashnodes["${index}"]
587c2fbfb3SApril Chin
597c2fbfb3SApril Chin		for i in "${node.xlfd[@]}" ; do
607c2fbfb3SApril Chin			IFS='-' read dummy a b c d e f <<<"$i"
617c2fbfb3SApril Chin
627c2fbfb3SApril Chin			if [[ "$a" == "" ]] ; then
637c2fbfb3SApril Chin				a="$dummy"
647c2fbfb3SApril Chin			fi
657c2fbfb3SApril Chin
667c2fbfb3SApril Chin			[[ "$a" == "" ]] && a='-'
677c2fbfb3SApril Chin			[[ "$b" == "" ]] && b='-'
687c2fbfb3SApril Chin			[[ "$c" == "" ]] && c='-'
697c2fbfb3SApril Chin
707c2fbfb3SApril Chin			if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then
717c2fbfb3SApril Chin			#if ! (unset dest_tree.l1["$a"]) ; then
727c2fbfb3SApril Chin				typeset -A dest_tree.l1["$a"].l2
737c2fbfb3SApril Chin			fi
747c2fbfb3SApril Chin
757c2fbfb3SApril Chin			if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then
767c2fbfb3SApril Chin			#if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then
777c2fbfb3SApril Chin				typeset -A dest_tree.l1["$a"].l2["$b"].l3
787c2fbfb3SApril Chin			fi
797c2fbfb3SApril Chin
807c2fbfb3SApril Chin			if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then
817c2fbfb3SApril Chin				typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries
827c2fbfb3SApril Chin			fi
837c2fbfb3SApril Chin
847c2fbfb3SApril Chin			typeset new_index
857c2fbfb3SApril Chin			if [[ "${tree_mode}" == "leaf_name" ]] ; then
867c2fbfb3SApril Chin				new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 ))
877c2fbfb3SApril Chin			else
887c2fbfb3SApril Chin				new_index="${node.name}"
897c2fbfb3SApril Chin
907c2fbfb3SApril Chin				# skip if the leaf node already exists
917c2fbfb3SApril Chin				if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then
927c2fbfb3SApril Chin					continue
937c2fbfb3SApril Chin				fi
947c2fbfb3SApril Chin			fi
957c2fbfb3SApril Chin
967c2fbfb3SApril Chin			add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}"
977c2fbfb3SApril Chin		done
987c2fbfb3SApril Chin	done
997c2fbfb3SApril Chin
1007c2fbfb3SApril Chin	return 0
1017c2fbfb3SApril Chin}
1027c2fbfb3SApril Chin
1037c2fbfb3SApril Chin# "built_tree1" and "built_tree2" are identical except the way how they test
1047c2fbfb3SApril Chin# whether a variable exists:
1057c2fbfb3SApril Chin# - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable
1067c2fbfb3SApril Chin#    as non-zero length content
1077c2fbfb3SApril Chin# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell
1087c2fbfb3SApril Chinfunction build_tree2
1097c2fbfb3SApril Chin{
1107c2fbfb3SApril Chin#set -o errexit -o xtrace
1117c2fbfb3SApril Chin	typeset index
1127c2fbfb3SApril Chin	typeset s
1137c2fbfb3SApril Chin	typeset i
1147c2fbfb3SApril Chin	typeset dummy
1157c2fbfb3SApril Chin	typeset a b c d e f
1167c2fbfb3SApril Chin
1177c2fbfb3SApril Chin	nameref dest_tree="$1" # destination tree
1187c2fbfb3SApril Chin	nameref srcdata="$2"   # source data
1197c2fbfb3SApril Chin	typeset tree_mode="$3" # mode to define the type of leads
1207c2fbfb3SApril Chin
1217c2fbfb3SApril Chin	typeset -A dest_tree.l1
1227c2fbfb3SApril Chin
1237c2fbfb3SApril Chin	for index in "${!srcdata.hashnodes[@]}" ; do
1247c2fbfb3SApril Chin		nameref node=srcdata.hashnodes["${index}"]
1257c2fbfb3SApril Chin
1267c2fbfb3SApril Chin		for i in "${node.xlfd[@]}" ; do
1277c2fbfb3SApril Chin			IFS='-' read dummy a b c d e f <<<"$i"
1287c2fbfb3SApril Chin
1297c2fbfb3SApril Chin			if [[ "$a" == "" ]] ; then
1307c2fbfb3SApril Chin				a="$dummy"
1317c2fbfb3SApril Chin			fi
1327c2fbfb3SApril Chin
1337c2fbfb3SApril Chin			[[ "$a" == "" ]] && a='-'
1347c2fbfb3SApril Chin			[[ "$b" == "" ]] && b='-'
1357c2fbfb3SApril Chin			[[ "$c" == "" ]] && c='-'
1367c2fbfb3SApril Chin
1377c2fbfb3SApril Chin			#if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then
1387c2fbfb3SApril Chin			if ! (unset dest_tree.l1["$a"]) ; then
1397c2fbfb3SApril Chin				typeset -A dest_tree.l1["$a"].l2
1407c2fbfb3SApril Chin			fi
1417c2fbfb3SApril Chin
1427c2fbfb3SApril Chin			#if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then
1437c2fbfb3SApril Chin			if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then
1447c2fbfb3SApril Chin				typeset -A dest_tree.l1["$a"].l2["$b"].l3
1457c2fbfb3SApril Chin			fi
1467c2fbfb3SApril Chin
1477c2fbfb3SApril Chin			if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then
1487c2fbfb3SApril Chin				typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries
1497c2fbfb3SApril Chin			fi
1507c2fbfb3SApril Chin
1517c2fbfb3SApril Chin			typeset new_index
1527c2fbfb3SApril Chin			if [[ "${tree_mode}" == "leaf_name" ]] ; then
1537c2fbfb3SApril Chin				new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 ))
1547c2fbfb3SApril Chin			else
1557c2fbfb3SApril Chin				new_index="${node.name}"
1567c2fbfb3SApril Chin
1577c2fbfb3SApril Chin				# skip if the leaf node already exists
1587c2fbfb3SApril Chin				if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then
1597c2fbfb3SApril Chin					continue
1607c2fbfb3SApril Chin				fi
1617c2fbfb3SApril Chin			fi
1627c2fbfb3SApril Chin
1637c2fbfb3SApril Chin			add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}"
1647c2fbfb3SApril Chin		done
1657c2fbfb3SApril Chin	done
1667c2fbfb3SApril Chin
1677c2fbfb3SApril Chin	return 0
1687c2fbfb3SApril Chin}
1697c2fbfb3SApril Chin
1707c2fbfb3SApril Chin
1717c2fbfb3SApril Chinfunction add_tree_leaf
1727c2fbfb3SApril Chin{
1737c2fbfb3SApril Chin	nameref tree_leafnode="$1"
1747c2fbfb3SApril Chin	nameref data_node=srcdata.hashnodes["$2"]
1757c2fbfb3SApril Chin	typeset add_mode="$3"
1767c2fbfb3SApril Chin
1777c2fbfb3SApril Chin	case "${add_mode}" in
1787c2fbfb3SApril Chin		"leaf_name")
1797c2fbfb3SApril Chin			tree_leafnode="${data_node.name}"
1807c2fbfb3SApril Chin			return 0
1817c2fbfb3SApril Chin			;;
1827c2fbfb3SApril Chin		"leaf_compound")
1837c2fbfb3SApril Chin			tree_leafnode=(
1847c2fbfb3SApril Chin				typeset name="${data_node.name}"
1857c2fbfb3SApril Chin				typeset -a filenames=( "${data_node.filenames[@]}" )
1867c2fbfb3SApril Chin				typeset -a comments=( "${data_node.comments[@]}" )
1877c2fbfb3SApril Chin				typeset -a xlfd=( "${data_node.xlfd[@]}" )
1887c2fbfb3SApril Chin			)
1897c2fbfb3SApril Chin			return 0
1907c2fbfb3SApril Chin			;;
1917c2fbfb3SApril Chin		*)
1927c2fbfb3SApril Chin			print -u2 -f "ERROR: Unknown mode %s in add_tree_leaf\n" "${add_mode}"
1937c2fbfb3SApril Chin			return 1
1947c2fbfb3SApril Chin			;;
1957c2fbfb3SApril Chin	esac
1967c2fbfb3SApril Chin
1977c2fbfb3SApril Chin	# not reached
1987c2fbfb3SApril Chin	return 1
1997c2fbfb3SApril Chin}
2007c2fbfb3SApril Chin
2017c2fbfb3SApril Chin# "mysrcdata_local" and "mysrcdata_global" must be identical
2027c2fbfb3SApril Chintypeset mysrcdata_global=(
2037c2fbfb3SApril Chin	typeset -A hashnodes=(
2047c2fbfb3SApril Chin		[abcd]=(
2057c2fbfb3SApril Chin			name='abcd'
2067c2fbfb3SApril Chin			typeset -a xlfd=(
2077c2fbfb3SApril Chin				'-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1'
2087c2fbfb3SApril Chin				'-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific'
2097c2fbfb3SApril Chin				'-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific'
2107c2fbfb3SApril Chin			)
2117c2fbfb3SApril Chin			typeset -a comments=(
2127c2fbfb3SApril Chin				'comment 1'
2137c2fbfb3SApril Chin				'comment 2'
2147c2fbfb3SApril Chin				'comment 3'
2157c2fbfb3SApril Chin			)
2167c2fbfb3SApril Chin			typeset -a filenames=(
2177c2fbfb3SApril Chin				'/home/foo/abcd_1'
2187c2fbfb3SApril Chin				'/home/foo/abcd_2'
2197c2fbfb3SApril Chin				'/home/foo/abcd_3'
2207c2fbfb3SApril Chin			)
2217c2fbfb3SApril Chin		)
2227c2fbfb3SApril Chin	)
2237c2fbfb3SApril Chin)
2247c2fbfb3SApril Chin
2257c2fbfb3SApril Chinmytree_global1=()
2267c2fbfb3SApril Chinmytree_global2=()
2277c2fbfb3SApril Chin
2287c2fbfb3SApril Chinfunction main
2297c2fbfb3SApril Chin{
2307c2fbfb3SApril Chin	# "mysrcdata_local" and "mysrcdata_global" must be identical
2317c2fbfb3SApril Chin	typeset mysrcdata_local=(
2327c2fbfb3SApril Chin		typeset -A hashnodes=(
2337c2fbfb3SApril Chin			[abcd]=(
2347c2fbfb3SApril Chin				name='abcd'
2357c2fbfb3SApril Chin				typeset -a xlfd=(
2367c2fbfb3SApril Chin					'-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1'
2377c2fbfb3SApril Chin					'-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific'
2387c2fbfb3SApril Chin					'-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific'
2397c2fbfb3SApril Chin				)
2407c2fbfb3SApril Chin				typeset -a comments=(
2417c2fbfb3SApril Chin					'comment 1'
2427c2fbfb3SApril Chin					'comment 2'
2437c2fbfb3SApril Chin					'comment 3'
2447c2fbfb3SApril Chin				)
2457c2fbfb3SApril Chin				typeset -a filenames=(
2467c2fbfb3SApril Chin					'/home/foo/abcd_1'
2477c2fbfb3SApril Chin					'/home/foo/abcd_2'
2487c2fbfb3SApril Chin					'/home/foo/abcd_3'
2497c2fbfb3SApril Chin				)
2507c2fbfb3SApril Chin			)
2517c2fbfb3SApril Chin		)
2527c2fbfb3SApril Chin	)
2537c2fbfb3SApril Chin
2547c2fbfb3SApril Chin	#### Build tree using global tree variables
2557c2fbfb3SApril Chin	build_tree1 mytree_global1 mysrcdata_global leaf_compound || \
2567c2fbfb3SApril Chin		err_exit 'build_tree1 mytree_global1 mysrcdata_global leaf_compound returned an error'
25734f9b3eeSRoland Mainz	(( $(print -r -- "${mytree_global1}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global1' too small"
2587c2fbfb3SApril Chin
2597c2fbfb3SApril Chin	build_tree2 mytree_global2 mysrcdata_global leaf_compound || \
2607c2fbfb3SApril Chin		err_exit 'build_tree2 mytree_global2 mysrcdata_global leaf_compound returned an error'
26134f9b3eeSRoland Mainz	(( $(print -r -- "${mytree_global2}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global2' too small"
2627c2fbfb3SApril Chin
2637c2fbfb3SApril Chin
2647c2fbfb3SApril Chin	#### build tree using local tree variables
2657c2fbfb3SApril Chin	mytree_local1=()
2667c2fbfb3SApril Chin	mytree_local2=()
2677c2fbfb3SApril Chin
2687c2fbfb3SApril Chin	build_tree1 mytree_local1 mysrcdata_local leaf_compound || \
2697c2fbfb3SApril Chin		err_exit 'build_tree1 mytree_local1 mysrcdata_local leaf_compound returned an error'
27034f9b3eeSRoland Mainz	(( $(print -r -- "${mytree_local1}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local1' too small"
2717c2fbfb3SApril Chin
2727c2fbfb3SApril Chin	build_tree2 mytree_local2 mysrcdata_local leaf_compound || \
2737c2fbfb3SApril Chin		err_exit 'build_tree2 mytree_local2 mysrcdata_local leaf_compound returned an error'
27434f9b3eeSRoland Mainz	(( $(print -r -- "${mytree_local2}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local2' too small"
2757c2fbfb3SApril Chin
2767c2fbfb3SApril Chin
2777c2fbfb3SApril Chin	#### Compare treess
2787c2fbfb3SApril Chin	if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then
27934f9b3eeSRoland Mainz		err_exit "compound trees 'mytree_global1' and 'mytree_local1' not identical"
2807c2fbfb3SApril Chin	fi
2817c2fbfb3SApril Chin
2827c2fbfb3SApril Chin	if [[ "${mytree_global1}" != "${mytree_global2}" ]] ; then
28334f9b3eeSRoland Mainz		err_exit "compound trees 'mytree_global1' and 'mytree_global2' not identical"
2847c2fbfb3SApril Chin	fi
2857c2fbfb3SApril Chin
2867c2fbfb3SApril Chin	if [[ "${mytree_local1}" != "${mytree_local2}" ]] ; then
28734f9b3eeSRoland Mainz		err_exit "compound trees 'mytree_local1' and 'mytree_local2' not identical"
2887c2fbfb3SApril Chin	fi
2897c2fbfb3SApril Chin
2907c2fbfb3SApril Chin
2917c2fbfb3SApril Chin	#### test "unset" in a subshell
2927c2fbfb3SApril Chin	(  unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]'  ) || \
29334f9b3eeSRoland Mainz		err_exit "try 1: variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found"
2947c2fbfb3SApril Chin	(  unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]'  ) || \
29534f9b3eeSRoland Mainz		err_exit "try 2: variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found"
2967c2fbfb3SApril Chin
2977c2fbfb3SApril Chin	# remove parent node (array element) and then check whether the child is gone, too:
2987c2fbfb3SApril Chin	(
2997c2fbfb3SApril Chin		unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]'
30034f9b3eeSRoland Mainz		[[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]'} ]]
30134f9b3eeSRoland Mainz	) && err_exit "global: parent node removed (array element), child still exists"
3027c2fbfb3SApril Chin	(
3037c2fbfb3SApril Chin		unset 'mytree_local1.l1[urw].l2[itc zapfdingbats]'
30434f9b3eeSRoland Mainz		[[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]]
30534f9b3eeSRoland Mainz	) && err_exit "local: parent node removed (array element), child still exists"
3067c2fbfb3SApril Chin
3077c2fbfb3SApril Chin	# remove parent node  (array variable) and then check whether the child is gone, too:
3087c2fbfb3SApril Chin	(
3097c2fbfb3SApril Chin		unset 'mytree_local1.l1[urw].l2'
31034f9b3eeSRoland Mainz		[[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]]
31134f9b3eeSRoland Mainz	) && err_exit "global: parent node removed (array variable), child still exists"
3127c2fbfb3SApril Chin	(
3137c2fbfb3SApril Chin		unset 'mytree_local1.l1[urw].l2'
31434f9b3eeSRoland Mainz		[[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]]
31534f9b3eeSRoland Mainz	) && err_exit "local: parent node removed (array variable), child still exists"
3167c2fbfb3SApril Chin
3177c2fbfb3SApril Chin
3187c2fbfb3SApril Chin	#### test "unset" and compare trees
3197c2fbfb3SApril Chin	unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ||
32034f9b3eeSRoland Mainz		err_exit "variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found"
3217c2fbfb3SApril Chin
3227c2fbfb3SApril Chin	[[ "${mytree_global1}" != "${mytree_local1}" ]] || err_exit "mytree_global1 and mytree_local1 should differ"
3237c2fbfb3SApril Chin
3247c2fbfb3SApril Chin	unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ||
32534f9b3eeSRoland Mainz		err_exit "variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found"
3267c2fbfb3SApril Chin
3277c2fbfb3SApril Chin	# Compare trees (after "unset")
3287c2fbfb3SApril Chin	if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then
32934f9b3eeSRoland Mainz		err_exit "compound trees 'mytree_local1' and 'mytree_global1' not identical after unset"
3307c2fbfb3SApril Chin	fi
3317c2fbfb3SApril Chin}
3327c2fbfb3SApril Chin
3337c2fbfb3SApril Chinmain
3347c2fbfb3SApril Chinexit $((Errors))
335