#!/bin/bash
# Copyright 1999-2005 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header$

trap ":" INT QUIT TSTP
source /sbin/functions.sh
# Only source this when this is a livecd booting ...
[ -f /sbin/livecd-functions.sh ] && source /sbin/livecd-functions.sh
umask 022

try() {
	local errstr
	local retval=0
	
	if [ -c /dev/null ]; then
		errstr="$((eval $*) 2>&1 >/dev/null)"
	else
		errstr="$((eval $*) 2>&1)"
	fi
	retval=$?
	if [ "${retval}" -ne 0 ]
	then
		splash "critical" &

		echo -e "${ENDCOL}${NORMAL}[${BAD} oops ${NORMAL}]"
		echo
		eerror "The \"${1}\" command failed with error:"
		echo
		echo "${errstr#*: }"
		echo
		eerror "Since this is a critical task, startup cannot continue."
		echo
		/sbin/sulogin ${CONSOLE}
		einfo "Unmounting filesystems"
		if [ -c /dev/null ]; then
			/bin/mount -a -o remount,ro &>/dev/null
		else
			/bin/mount -a -o remount,ro
		fi
		einfo "Rebooting"
		/sbin/reboot -f
	fi
	
	return ${retval}
}

# Check that $1 exists ...
check_statedir() {
	[ -z "$1" ] && return 0

	if [ ! -d "$1" ] ; then
		if ! mkdir -p "$1" &>/dev/null ; then
			splash "critical" &
			echo
			eerror "For Gentoo to function properly, \"$1\" needs to exist."
			if [[ ${RC_FORCE_AUTO} == "yes" ]] ; then
				eerror "Attempting to create \"$1\" for you ..."
				mount -o remount,rw /
				mkdir -p "$1"
			else
				eerror "Please mount your root partition read/write, and execute:"
				echo
				eerror "  # mkdir -p $1"
				echo; echo
				/sbin/sulogin ${CONSOLE}
			fi
			einfo "Unmounting filesystems"
			/bin/mount -a -o remount,ro &>/dev/null
			einfo "Rebooting"
			/sbin/reboot -f
		fi
	fi

	return 0
}

get_critical_services() {
	local x=
	CRITICAL_SERVICES=
	
	if [ -f "/etc/runlevels/${BOOTLEVEL}/.critical" ]
	then
		for x in $(< /etc/runlevels/${BOOTLEVEL}/.critical)
		do
			CRITICAL_SERVICES="${CRITICAL_SERVICES} ${x##*/}"
		done
	else
		CRITICAL_SERVICES="checkroot hostname modules checkfs localmount clock bootmisc"
	fi

	export CRITICAL_SERVICES

	return 0
}

# Save $1
argv1="$1"

# First time boot stuff goes here.  Note that 'sysinit' is an internal runlevel
# used to bring up local filesystems, and should not be started with /sbin/rc
# directly ...
if [ "${RUNLEVEL}" = "S" -a "${argv1}" = "sysinit" ]
then
	# Setup initial $PATH just in case
	PATH="/bin:/sbin:/usr/bin:/usr/sbin:${PATH}"

	# Help users recover their systems incase these go missing
	[ -c /dev/null ] && dev_null=1 || dev_null=0
	[ -c /dev/console ] && dev_console=1 || dev_console=0

	echo
	echo -e "${GOOD}Gentoo Linux${GENTOO_VERS}; ${BRACKET}http://www.gentoo.org/${NORMAL}"
	echo -e " Copyright 1999-2005 Gentoo Foundation; Distributed under the GPLv2"
	echo

	check_statedir /proc

	ebegin "Mounting proc at /proc"
	if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
		mntcmd=$(get_mount_fstab /proc)
	else
		unset mntcmd
	fi
	try mount -n ${mntcmd:--t proc proc /proc}
	eend $?

	# Read off the kernel commandline to see if there's any special settings
	# especially check to see if we need to set the  CDBOOT environment variable
	# Note: /proc MUST be mounted
	[ -f /sbin/livecd-functions.sh ] && livecd_read_commandline

	if [ "$(get_KV)" -ge "$(KV_to_int '2.6.0')" ] ; then
		if [[ -d /sys ]] ; then
			ebegin "Mounting sysfs at /sys"
			if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
				mntcmd=$(get_mount_fstab /sys)
			else
				unset mntcmd
			fi
			try mount -n ${mntcmd:--t sysfs sysfs /sys}
			eend $?
		else
			ewarn "No /sys to mount sysfs needed in 2.6 and later kernels!"
		fi
	fi

	check_statedir /dev

	# Fix weird bug where there is a /dev/.devfsd in a unmounted /dev
	devfs_automounted="no"
	if [ -e "/dev/.devfsd" ]
	then
		mymounts="$(awk '($3 == "devfs") { print "yes"; exit 0 }' /proc/mounts)"
		if [ "${mymounts}" != "yes" ]
		then
			rm -f /dev/.devfsd
		else
			devfs_automounted="yes"
		fi
	fi

	# Try to figure out how the user wants /dev handled
	#  - check $RC_DEVICES from /etc/conf.d/rc
	#  - check boot parameters
	#  - make sure the required binaries exist
	#  - make sure the kernel has support
	if [ "${RC_DEVICES}" = "static" ]
	then
		ebegin "Using existing device nodes in /dev"
		eend 0
	else
		fellback_to_devfs="no"
		case "${RC_DEVICES}" in
			devfs)	devfs="yes"
					udev="no"
					;;
			udev)	devfs="yes"
					udev="yes"
					fellback_to_devfs="yes"
					;;
			auto|*)	devfs="yes"
					udev="yes"
					;;
		esac

		# Check udev prerequisites and kernel params
		if [ "${udev}" = "yes" ]
		then
			if get_bootparam "noudev" || \
			   [ ! -x /sbin/udev -o ${devfs_automounted} = "yes" ] || \
			   [ "$(get_KV)" -lt "$(KV_to_int '2.6.0')" ]
			then
				udev="no"
			fi
		fi

		# Check devfs prerequisites and kernel params
		if [ "${devfs}" = "yes" ]
		then
			if get_bootparam "nodevfs" || [ "${udev}" = "yes" ]
			then
				devfs="no"
			fi
		fi

		# Actually start setting up /dev now
		if [[ ${udev} == "yes" ]] ; then
			start_addon udev

		# With devfs, /dev can be mounted by the kernel ...
		elif [[ ${devfs} == "yes" ]] ; then
			start_addon devfs

			# Did the user want udev in the config file but for 
			# some reason, udev support didnt work out ?
			if [[ ${fellback_to_devfs} == "yes" ]] ; then
				ewarn "You wanted udev but support for it was not available!"
				ewarn "Please review your system after it's booted!"
			fi
		fi

		# OK, if we got here, things are probably not right :)
		if [[ ${devfs} == "no" && ${udev} == "no" ]] ; then
			clear
			echo
			einfo "The Gentoo Linux system initialization scripts have detected that"
			einfo "your system does not support UDEV.  Since Gentoo Linux has been"
			einfo "designed with dynamic /dev in mind, it is highly suggested that you"
			einfo "emerge sys-fs/udev and configure your system to use it."
			einfo "Please read the Gentoo Handbook for more information!"
			echo
			einfo "    http://www.gentoo.org/doc/en/handbook/"
			echo
			einfo "Thanks for using Gentoo! :)"
			echo
			read -t 15 -p "(hit Enter to continue or wait 15 seconds ...)"
		fi
	fi

	# From linux-2.5.68 we need to mount /dev/pts again ...
	if [ "$(get_KV)" -ge "$(KV_to_int '2.5.68')" ]
	then
		have_devpts="$(awk '($2 == "devpts") { print "yes"; exit 0 }' /proc/filesystems)"

		if [ "${have_devpts}" = "yes" ]
		then
			# Only try to create /dev/pts if we have /dev mounted dynamically,
			# else it might fail as / might be still mounted readonly.
			if [ ! -d /dev/pts ] && \
			   [ "${devfs}" = "yes" -o "${udev}" = "yes" ]
			then
				# Make sure we have /dev/pts
				mkdir -p /dev/pts &>/dev/null || \
					ewarn "Could not create /dev/pts!"
			fi

			if [[ -d /dev/pts ]] ; then
				ebegin "Mounting devpts at /dev/pts"
				if [[ ${RC_USE_FSTAB} = "yes" ]] ; then
					mntcmd=$(get_mount_fstab /dev/pts)
				else
					unset mntcmd
				fi
				try mount -n ${mntcmd:--t devpts -o gid=5,mode=0620 devpts /dev/pts}
				eend $?
			fi
		fi
	fi

	# Start logging console output since we have all /dev stuff setup
	bootlog start

	# Swap needs to be activated *after* /dev has been fully setup so that
	# the fstab can be properly parsed.  This first pass we send to /dev/null
	# in case the user has swap points setup on different partitions.  We 
	# will run swapon again in localmount and that one will report errors.
	ebegin "Activating (possible) swap"
	/sbin/swapon -a >& /dev/null
	eend 0

	# Set the console loglevel to 1 for a cleaner boot
	# the logger should anyhow dump the ring-0 buffer at start to the
	# logs, and that with dmesg can be used to check for problems
	/bin/dmesg -n 1

	# We set the forced softlevel from the kernel command line
	# It needs to be run right after proc is mounted for the
	# boot runlevel
	setup_defaultlevels

	# $BOOT can be used by rc-scripts to test if it is the first time
	# the 'boot' runlevel is executed.  Now also needed by some stuff in
	# the 'sysinit' runlevel ...
	export BOOT="yes"

	start_critical_service() {
		(
		local retval=
		local service=$1
		# Needed for some addons like dm-crypt that starts in critical services
		local myservice=$1

		source "/etc/init.d/${service}" || eerror "Failed to source /etc/init.d/${service}"
		retval=$?
		[ "${retval}" -ne 0 ] && return "${retval}"
		[ -e "/etc/conf.d/${service}" ] && source "/etc/conf.d/${service}"
		source /etc/rc.conf

		start || eerror "Failed to start /etc/init.d/${service}"
		retval=$?

		return "${retval}"
		)
	}

	# We first try to find a locally defined list of critical services
	# for a particular runlevel.  If we cannot find it, we use the
	# defaults.
	get_critical_services

	splash "rc_init" "${argv1}"

	# We do not want to break compatibility, so we do not fully integrate
	# these into /sbin/rc, but rather start them by hand ...
	for x in ${CRITICAL_SERVICES}
	do
		splash "svc_start" "${x}"

		if ! start_critical_service "${x}"
		then
			splash "critical" &>/dev/null &
			
			echo
			eerror "One of more critical startup scripts failed to start!"
			eerror "Please correct this, and reboot ..."
			echo; echo
			/sbin/sulogin ${CONSOLE}
			einfo "Unmounting filesystems"
			/bin/mount -a -o remount,ro &>/dev/null
			einfo "Rebooting"
			/sbin/reboot -f
		fi

		splash "svc_started" "${x}" "0"
	done

	# /var/log should be writable now, so starting saving the boot output
	bootlog sync

	# have to run this after /var/run is mounted rw #85304
	if [ -x /sbin/irqbalance -a "$(get_KV)" -ge "$(KV_to_int '2.5.0')" ]
	then
		ebegin "Starting irqbalance"
		/sbin/irqbalance
		eend $?
	fi

	# Check that $svcdir exists ...
	check_statedir "${svcdir}"

	# Should we use tmpfs/ramfs/ramdisk for caching dependency and 
	# general initscript data?  Note that the 'gentoo=<fs>' kernel 
	# option should override any other setting ...
	for fs in tmpfs ramfs ramdisk
	do
		if get_bootparam "${fs}"
		then
			svcmount="yes"
			svcfstype="${fs}"
			break
		fi
	done
	if [ "${svcmount}" = "yes" ]
	then
		ebegin "Mounting ${svcfstype} at ${svcdir}"
		case "${svcfstype}" in
		ramfs)
			try mount -t ramfs svcdir "${svcdir}" \
				-o rw,mode=0755,size="${svcsize}"k
			;;
		ramdisk)
			try dd if=/dev/zero of=/dev/ram0 bs=1k count="${svcsize}"
			try /sbin/mke2fs -i 1024 -vm0 /dev/ram0 "${svcsize}"
			try mount -t ext2 /dev/ram0 "${svcdir}" -o rw
			;;
		tmpfs|*)
			try mount -t tmpfs svcdir "${svcdir}" \
				-o rw,mode=0755,size="${svcsize}"k
			;;
		esac
		eend 0
	fi

	# If booting off CD, we want to update inittab before setting the runlevel
	if [ -f "/sbin/livecd-functions.sh" -a -n "${CDBOOT}" ]
	then
		ebegin "Updating inittab"
		livecd_fix_inittab
		eend $?
		/sbin/telinit q &>/dev/null
	fi

	# Clear $svcdir from stale entries, but leave the caches around, as it
	# should help speed things up a bit
	rm -rf $(ls -d1 "${svcdir}/"* 2>/dev/null | \
	         grep -ve '\(depcache\|deptree\|envcache\)')

	# Update the dependency cache
	/sbin/depscan.sh -u

	# Now that the dependency cache are up to date, make sure these
	# are marked as started ...
	(
		# Needed for mark_service_started()
		source "${svclib}/sh/rc-services.sh"
		
		for x in ${CRITICAL_SERVICES}
		do
			mark_service_started "${x}"
		done
	)

	# If the user's /dev/null or /dev/console are missing, we 
	# should help them out and explain how to rectify the situation
	if [ ${dev_null} -eq 0 -o ${dev_console} -eq 0 ] \
	    && [ -e /usr/share/baselayout/issue.devfix ]
	then
		# Backup current /etc/issue
		if [ -e /etc/issue -a ! -e /etc/issue.devfix ]
		then
			mv /etc/issue /etc/issue.devfix
		fi

		cp /usr/share/baselayout/issue.devfix /etc/issue
	fi

	# Setup login records ... this has to be done here because when 
	# we exit this runlevel, init will write a boot record to utmp
	# If /var/run is readonly, then print a warning, not errors
	if touch /var/run/utmp 2>/dev/null
	then
		> /var/run/utmp
		touch /var/log/wtmp
		chgrp utmp /var/run/utmp /var/log/wtmp
		chmod 0664 /var/run/utmp /var/log/wtmp
		# Remove /var/run/utmpx (bug from the past)
		rm -f /var/run/utmpx
	else
		ewarn "Skipping /var/run/utmp initialization (ro root?)"
	fi

	# sysinit is now done, so allow init scripts to run normally
	[[ -e /dev/.rcsysinit ]] && rm -f /dev/.rcsysinit

	# All done logging
	bootlog quit

	exit 0
fi # Sysinit ends here

if [ "${RUNLEVEL}" = "S" -a "${argv1}" = "boot" ]
then
	setup_defaultlevels

	if [ -n "${DEFAULTLEVEL}" -a "${DEFAULTLEVEL}" != "default" ]
	then
		# Setup our default runlevel runlevel that will be run
		# the first time /sbin/rc is called with argv1 != sysinit|boot
		echo "${DEFAULTLEVEL}" > "${svcdir}/ksoftlevel"
	fi
	
	# $BOOT can be used by rc-scripts to test if it is the first time
	# the 'boot' runlevel is executed
	export BOOT="yes"

	# We reset argv1 to the bootlevel given on the kernel command line
	# if there is one
	argv1="${BOOTLEVEL}"
	
elif [ "${RUNLEVEL}" != "S" -a -e "${svcdir}/ksoftlevel" ]
then
	argv1="$(< ${svcdir}/ksoftlevel)"
	rm -f "${svcdir}/ksoftlevel"
fi

source "${svclib}/sh/rc-services.sh"
source "${svclib}/sh/rc-daemon.sh"

if [ -f "${svcdir}/softlevel" ]
then
	# Set OLDSOFTLEVEL if we had a valid SOFTLEVEL
	export OLDSOFTLEVEL="$(< ${svcdir}/softlevel)"
else
	export OLDSOFTLEVEL=
fi
	
if [ -z "${argv1}" ]
then
	if [ -f "${svcdir}/softlevel" ]
	then
		export SOFTLEVEL="$(< ${svcdir}/softlevel)"
	else
		export SOFTLEVEL="${BOOTLEVEL}"
	fi
else
	export SOFTLEVEL="${argv1}"
fi

if [ ! -f "${svcdir}/softlevel" ]
then
	echo "${SOFTLEVEL}" > "${svcdir}/softlevel"
fi

# For keeping a list of services that fails during boot/halt
if [ ! -d "${svcdir}/failed" ]
then
	mkdir -p -m 0755 "${svcdir}/failed"
else
	rm -rf "${svcdir}"/failed/*
fi

splash "rc_init" "${argv1}"

if [ "${SOFTLEVEL}" = "reboot" -o "${SOFTLEVEL}" = "shutdown" ]
then
	myscripts=

elif [ "${SOFTLEVEL}" = "single" ]
then
	get_critical_services

	myscripts="${CRITICAL_SERVICES}"
	
elif [ ! -d "/etc/runlevels/${SOFTLEVEL}" ]
then
	eerror "ERROR:  runlevel ${SOFTLEVEL} does not exist; exiting ..."
	exit 1
else
	myscripts=
	if [ "${SOFTLEVEL}" != "${BOOTLEVEL}" ]
	then
		# Normal runlevels *include* boot scripts
		mylevels="$(dolisting "/etc/runlevels/${SOFTLEVEL}/")"
		mylevels="${mylevels} $(dolisting /etc/runlevels/${BOOTLEVEL}/)"
	else
		# Non-normal runlevels don't include boot scripts as default
		mylevels="$(dolisting "/etc/runlevels/${SOFTLEVEL}/")"
	fi
	
	[ "${OLDSOFTLEVEL}" = "${BOOTLEVEL}" -o "${OLDSOFTLEVEL}" = "single" ] \
		&& /bin/dmesg -n 1
	
	for x in ${mylevels}
	do
		[ -L "${x}" ] && myscripts="${myscripts} ${x##*/}"
	done
fi

# The softscripts dir contains all scripts that belong to the
# runlevel specified in ${svcdir}/softlevel
# It needs to be a new directory, else when stopping the services
# and the old directory is not intact, things get broken

mkdir -p -m 0755 "${svcdir}/softscripts.new"

for x in ${myscripts} ; do
	if [[ ! -e /etc/init.d/${x} ]] ; then
		ewarn "WARNING:  /etc/init.d/${x} missing; skipping ..."
		continue
	fi
	# The -f eliminates a warning if the symlink already exists,
	# which can happen if a service is in both the boot level and
	# the current "normal" runlevel
	ln -snf "/etc/init.d/${x}" "${svcdir}/softscripts.new/${x}"
done

dep_stop() {
	local x=
	local dep=
	local needsme=
	local myservice="${1##*/}"
	local depservice=

	if ! service_started "${myservice}"
	then
		return 0
	fi
	
	# Candidate for zapping
	if [ ! -L "${svcdir}/softscripts.new/${myservice}" ]
	then
		# If this is a 'net' service, we do not want to stop it if it was
		# not in the previous runlevel, and we are not shutting down,
		# rebooting or going to single runlevel.  This is because the user
		# might have started it (net.ppp?), or possibly hotplug ...
		if net_service "${myservice}" && \
		   [ "${SOFTLEVEL}" != "reboot" -a \
		     "${SOFTLEVEL}" != "shutdown" -a \
		     "${SOFTLEVEL}" != "single" ]
		then
			if [ -n "${OLDSOFTLEVEL}" ] && \
			   ! in_runlevel "${myservice}" "${OLDSOFTLEVEL}"
			then
				# This service is not in the previous runlevel, so
				# do not stop it ...
				return 0
			fi
		fi

		# Should not work for 'use'
		if [ -z "$(needsme "${myservice}")" ]
		then
			# Nothing depends on me
			stop_service "${myservice}"
		else
			# Something may depend on me
			needsme=0
			
			for dep in $(needsme "${myservice}")
			do
				if service_started "${dep}" && \
				   [ -L "${svcdir}/softscripts.new/${dep}" ]
				then
					# This dep is valid
					needsme=1
					
					break
				fi
			done
			
			if [ "${needsme}" -eq 0 ]
			then
				stop_service "${myservice}"
			fi
		fi
	fi
}

# Stop services
if [[ ${SOFTLEVEL} != "single" && \
      ${SOFTLEVEL} != "reboot" && \
      ${SOFTLEVEL} != "shutdown" ]]
then
	for i in $(dolisting "${svcdir}/started/") ; do
		dep_stop "${i}"
	done
else
	get_critical_services

	is_critical_service() {
		local x
		local myservice=${1##*/}

		for x in ${CRITICAL_SERVICES} ; do
			[[ ${myservice} == "${x}" ]] && return 0
		done

		return 1
	}
	
	# First stop non critical services
	for i in $(dolisting "${svcdir}/started/")
	do
		if [ -n "${LOGGER_SERVICE}" ]
		then
			# Only stop it if the logger do not depends on it
			if ! query_before "${i##*/}" "${LOGGER_SERVICE}"
			then
				continue
			fi
		fi

		# Do not stop critical services just yet
		is_critical_service "${i}" || dep_stop "${i}"
	done

	# Now stop the logger if running
	if [ -n "${LOGGER_SERVICE}" ]
	then
		dep_stop "${LOGGER_SERVICE}"
	fi

	# Now stop the rest
	for i in $(dolisting "${svcdir}/started/")
	do
		dep_stop "${i}"
	done
fi

# Only change softlevel AFTER all the services have been stopped,
# else they will not get the depend's right (wrong SOFTLEVEL)

echo "${SOFTLEVEL}" > "${svcdir}/softlevel"

if [[ ${SOFTLEVEL} == "reboot" || ${SOFTLEVEL} == "shutdown" ]] ; then
	source /sbin/functions.sh
	
	# Clear $svcdir from stale entries, but leave the caches around, as it
	# should help speed things up a bit
	rm -rf $(ls -d1 "${svcdir}/"* 2>/dev/null | \
	         grep -ve '\(depcache\|deptree\|envcache\)')
	
	source /etc/init.d/halt.sh
	
	if [[ ${SOFTLEVEL} == "reboot" ]] ; then
		source /etc/init.d/reboot.sh
	else
		source /etc/init.d/shutdown.sh
	fi
	
	# Should never get here
	exit 0
fi

# Move the old softscritps directory to a different one
# and make the new softscripts directory the current

mv -f "${svcdir}/softscripts" "${svcdir}/softscripts.old"
mv -f "${svcdir}/softscripts.new" "${svcdir}/softscripts"

dep_start() {
	local myservice="${1##*/}"

	[ ! -L "${svcdir}/softscripts/${myservice}" ] && continue

	# Only start a script if it isn't already running
	service_started "${myservice}" || schedule_service_startup "${myservice}"
}

get_critical_services

EXTRA_SOFTSCRIPTS="${CRITICAL_SERVICES}"

if [ -n "${LOGGER_SERVICE}" -a -L "${svcdir}/softscripts/${LOGGER_SERVICE}" ]
then
	service_started "${LOGGER_SERVICE}" || \
		EXTRA_SOFTSCRIPTS="${EXTRA_SOFTSCRIPTS} ${LOGGER_SERVICE}"
fi

if [ "${SOFTLEVEL}" != "${BOOTLEVEL}" ]
then
	for i in $(dolisting "/etc/runlevels/${BOOTLEVEL}/")
	do
		[ -L "${svcdir}/softscripts/${i##*/}" ] && \
			EXTRA_SOFTSCRIPTS="${EXTRA_SOFTSCRIPTS} ${i##*/}"
	done
fi

# Start scripts
for i in ${EXTRA_SOFTSCRIPTS} $(dolisting "${svcdir}/softscripts/")
do
	dep_start "${i##*/}"
done

# Wait for any services that may still be running ...
[ "${RC_PARALLEL_STARTUP}" = "yes" ] && wait

# Clean the old runlevel
rm -rf "${svcdir}/softscripts.old" &>/dev/null

# Depends gets nuked, so update them
# (this problem should be solved now, but i think it will be a good idea
#  to recreate the deps after a change in runlevel)

#/sbin/depscan.sh &>/dev/null

# We want devfsd running after a change of runlevel (this is mostly if we return
# from runlevel 'single')
if [ -z "`ps --no-heading -C 'devfsd'`" -a \
     -n "`gawk '/\/dev devfs/ { print }' /proc/mounts 2>/dev/null`" ]
then
	if [ "${RC_DEVFSD_STARTUP}" != "no" ]
	then
		/sbin/devfsd /dev &>/dev/null
	fi
fi

# Runlevel end, so clear stale fail list
rm -rf "${svcdir}/failed" &>/dev/null

# If we were in the boot runlevel, it is done now ...
[ -n "${BOOT}" ] && unset BOOT

splash "rc_exit"

# vim:ts=4
