14ad8b75dSGlen Barber#!/bin/sh 24ad8b75dSGlen Barber#- 3751c20d8SGlen Barber# Copyright (c) 2015-2017 The FreeBSD Foundation 44ad8b75dSGlen Barber# 54ad8b75dSGlen Barber# Portions of this software were developed by Glen Barber 64ad8b75dSGlen Barber# under sponsorship from the FreeBSD Foundation. 74ad8b75dSGlen Barber# 84ad8b75dSGlen Barber# Redistribution and use in source and binary forms, with or without 94ad8b75dSGlen Barber# modification, are permitted provided that the following conditions 104ad8b75dSGlen Barber# are met: 114ad8b75dSGlen Barber# 1. Redistributions of source code must retain the above copyright 124ad8b75dSGlen Barber# notice, this list of conditions and the following disclaimer. 134ad8b75dSGlen Barber# 2. Redistributions in binary form must reproduce the above copyright 144ad8b75dSGlen Barber# notice, this list of conditions and the following disclaimer in the 154ad8b75dSGlen Barber# documentation and/or other materials provided with the distribution. 164ad8b75dSGlen Barber# 174ad8b75dSGlen Barber# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 184ad8b75dSGlen Barber# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 194ad8b75dSGlen Barber# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 204ad8b75dSGlen Barber# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 214ad8b75dSGlen Barber# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 224ad8b75dSGlen Barber# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 234ad8b75dSGlen Barber# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 244ad8b75dSGlen Barber# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 254ad8b75dSGlen Barber# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 264ad8b75dSGlen Barber# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 274ad8b75dSGlen Barber# SUCH DAMAGE. 284ad8b75dSGlen Barber# 2986635d49SMitchell Horne# Common subroutines used to build arm, arm64, or RISC-V SD card images. 304ad8b75dSGlen Barber# 314ad8b75dSGlen Barber# 324ad8b75dSGlen Barber 334ad8b75dSGlen Barbercleanup() { 344ad8b75dSGlen Barber if [ -c "${DESTDIR}/dev/null" ]; then 354ad8b75dSGlen Barber umount_loop ${DESTDIR}/dev 2>/dev/null 364ad8b75dSGlen Barber fi 374ad8b75dSGlen Barber umount_loop ${DESTDIR} 384ad8b75dSGlen Barber if [ ! -z "${mddev}" ]; then 394ad8b75dSGlen Barber mdconfig -d -u ${mddev} 404ad8b75dSGlen Barber fi 414ad8b75dSGlen Barber 424ad8b75dSGlen Barber return 0 434ad8b75dSGlen Barber} 444ad8b75dSGlen Barber 454ad8b75dSGlen Barberumount_loop() { 464ad8b75dSGlen Barber DIR=$1 474ad8b75dSGlen Barber i=0 484ad8b75dSGlen Barber sync 494ad8b75dSGlen Barber while ! umount ${DIR}; do 504ad8b75dSGlen Barber i=$(( $i + 1 )) 514ad8b75dSGlen Barber if [ $i -ge 10 ]; then 524ad8b75dSGlen Barber # This should never happen. But, it has happened. 534ad8b75dSGlen Barber echo "Cannot umount(8) ${DIR}" 544ad8b75dSGlen Barber echo "Something has gone horribly wrong." 554ad8b75dSGlen Barber return 1 564ad8b75dSGlen Barber fi 574ad8b75dSGlen Barber sleep 1 584ad8b75dSGlen Barber done 594ad8b75dSGlen Barber 604ad8b75dSGlen Barber return 0 614ad8b75dSGlen Barber} 624ad8b75dSGlen Barber 634ad8b75dSGlen Barberarm_create_disk() { 646b6367baSEd Maste if [ $(sysctl -n kern.geom.part.mbr.enforce_chs) != 0 ]; then 656b6367baSEd Maste return 1 666b6367baSEd Maste fi 676b6367baSEd Maste 684ad8b75dSGlen Barber # Create the target raw file and temporary work directory. 6904b7fd00SGlen Barber chroot ${CHROOTDIR} gpart create -s ${PART_SCHEME} ${mddev} 70*2af03ebfSMitchell Horne 71*2af03ebfSMitchell Horne arm_create_partitions 72*2af03ebfSMitchell Horne 733f197b10SJose Luis Duran if [ "${PART_SCHEME}" = "GPT" ]; then 7438e4df10SEmmanuel Vadot chroot ${CHROOTDIR} gpart add -t efi -l efi -a 512k -s ${FAT_SIZE} ${mddev} 7538e4df10SEmmanuel Vadot chroot ${CHROOTDIR} gpart add -t freebsd-ufs -l rootfs -a 64k ${mddev} 7638e4df10SEmmanuel Vadot fi 773f197b10SJose Luis Duran if [ "${PART_SCHEME}" = "MBR" ]; then 78751c20d8SGlen Barber chroot ${CHROOTDIR} gpart add -t '!12' -a 512k -s ${FAT_SIZE} ${mddev} 7904b7fd00SGlen Barber chroot ${CHROOTDIR} gpart set -a active -i 1 ${mddev} 8004b7fd00SGlen Barber chroot ${CHROOTDIR} gpart add -t freebsd ${mddev} 81*2af03ebfSMitchell Horne chroot ${CHROOTDIR} gpart create -s bsd ${mddev}${BSDLABEL_SUFFIX} 82*2af03ebfSMitchell Horne chroot ${CHROOTDIR} gpart add -t freebsd-ufs -a 64k -b 64k ${mddev}${BSDLABEL_SUFFIX} 8338e4df10SEmmanuel Vadot fi 844ad8b75dSGlen Barber 85*2af03ebfSMitchell Horne # Create the EFI and UFS filesystems 86*2af03ebfSMitchell Horne chroot ${CHROOTDIR} newfs_msdos -L efi -F ${FAT_TYPE} /dev/${mddev}${EFIPART_SUFFIX} 87*2af03ebfSMitchell Horne chroot ${CHROOTDIR} newfs -U -L rootfs /dev/${mddev}${ROOTFSPART_SUFFIX} 88*2af03ebfSMitchell Horne 894ad8b75dSGlen Barber return 0 904ad8b75dSGlen Barber} 914ad8b75dSGlen Barber 9288feae84SGlen Barberarm_create_user() { 9388feae84SGlen Barber # Create a default user account 'freebsd' with the password 'freebsd', 9488feae84SGlen Barber # and set the default password for the 'root' user to 'root'. 95b07d911fSGlen Barber chroot ${CHROOTDIR} /usr/sbin/pw -R ${DESTDIR} \ 96f3ca4d91SGlen Barber groupadd freebsd -g 1001 97717a45fcSGlen Barber chroot ${CHROOTDIR} mkdir -p ${DESTDIR}/home/freebsd 98b07d911fSGlen Barber chroot ${CHROOTDIR} /usr/sbin/pw -R ${DESTDIR} \ 99f3ca4d91SGlen Barber useradd freebsd \ 10088feae84SGlen Barber -m -M 0755 -w yes -n freebsd -u 1001 -g 1001 -G 0 \ 101b07d911fSGlen Barber -c 'FreeBSD User' -d '/home/freebsd' -s '/bin/csh' 102b07d911fSGlen Barber chroot ${CHROOTDIR} /usr/sbin/pw -R ${DESTDIR} \ 103f3ca4d91SGlen Barber usermod root -w yes 10488feae84SGlen Barber 10588feae84SGlen Barber return 0 10688feae84SGlen Barber} 10788feae84SGlen Barber 1084fe984fdSEdward Tomasz Napieralaarm_setup_usb_otg() { 1094fe984fdSEdward Tomasz Napierala # Set up virtual serial port over USB OTG / device mode. 1104fe984fdSEdward Tomasz Napierala echo >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf 1114fe984fdSEdward Tomasz Napierala echo '# Required for USB OTG virtual serial port.' \ 1124fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf 1134fe984fdSEdward Tomasz Napierala echo 'notify 100 {' \ 1144fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf 1154fe984fdSEdward Tomasz Napierala echo ' match "system" "DEVFS";' \ 1164fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf 1174fe984fdSEdward Tomasz Napierala echo ' match "subsystem" "CDEV";' \ 1184fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf 1194fe984fdSEdward Tomasz Napierala echo ' match "type" "CREATE";' \ 1204fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf 1214fe984fdSEdward Tomasz Napierala echo ' match "cdev" "ttyU[0-9]+";' \ 1224fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf 1234fe984fdSEdward Tomasz Napierala echo ' action "/sbin/init q";' \ 1244fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf 1254fe984fdSEdward Tomasz Napierala echo '};' \ 1264fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/devd.conf 1274fe984fdSEdward Tomasz Napierala 1284fe984fdSEdward Tomasz Napierala echo '# USB OTG virtual serial port' \ 1294fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/ttys 1304fe984fdSEdward Tomasz Napierala echo 'ttyU0 "/usr/libexec/getty 3wire" vt100 onifconsole secure' \ 1314fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/ttys 1324fe984fdSEdward Tomasz Napierala echo 'ttyU1 "/usr/libexec/getty 3wire" vt100 onifconsole secure' \ 1334fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/etc/ttys 1344fe984fdSEdward Tomasz Napierala 1354fe984fdSEdward Tomasz Napierala echo '# Configure USB OTG; see usb_template(4).' \ 1364fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 1374fe984fdSEdward Tomasz Napierala echo 'hw.usb.template=3' \ 1384fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 1394fe984fdSEdward Tomasz Napierala echo 'umodem_load="YES"' \ 1404fe984fdSEdward Tomasz Napierala >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 1414fe984fdSEdward Tomasz Napierala} 1424fe984fdSEdward Tomasz Napierala 143a8d0ee75SEmmanuel Vadotarm64_setup_multicons() { 144a8d0ee75SEmmanuel Vadot if [ "${EMBEDDED_TARGET_ARCH}" != "aarch64" ]; then 145a8d0ee75SEmmanuel Vadot return 146a8d0ee75SEmmanuel Vadot fi 147a8d0ee75SEmmanuel Vadot 148a8d0ee75SEmmanuel Vadot echo '# Multiple console (serial+efi gop) enabled.' \ 149a8d0ee75SEmmanuel Vadot >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 150a8d0ee75SEmmanuel Vadot echo 'boot_multicons="YES"' \ 151a8d0ee75SEmmanuel Vadot >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 152a8d0ee75SEmmanuel Vadot echo 'boot_serial="YES"' \ 153a8d0ee75SEmmanuel Vadot >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 154a8d0ee75SEmmanuel Vadot} 155a8d0ee75SEmmanuel Vadot 15666e38012SEmmanuel Vadotarm_setup_fdt_overlays() { 15766e38012SEmmanuel Vadot if [ -z "${FDT_OVERLAYS}" ]; then 15866e38012SEmmanuel Vadot return 15966e38012SEmmanuel Vadot fi 16066e38012SEmmanuel Vadot 16166e38012SEmmanuel Vadot echo '# DTB OVERLAYS' \ 16266e38012SEmmanuel Vadot >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 16366e38012SEmmanuel Vadot echo "fdt_overlays=\"${FDT_OVERLAYS}\"" \ 16466e38012SEmmanuel Vadot >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 16566e38012SEmmanuel Vadot} 16666e38012SEmmanuel Vadot 1679de0425eSKyle Evansarm_setup_minimal_loader() { 1689de0425eSKyle Evans echo '# Disable the beastie menu and color' \ 1699de0425eSKyle Evans >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 1709de0425eSKyle Evans echo 'beastie_disable="YES"' \ 1719de0425eSKyle Evans >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 1729de0425eSKyle Evans echo 'loader_color="NO"' \ 1739de0425eSKyle Evans >> ${CHROOTDIR}/${DESTDIR}/boot/loader.conf 1749de0425eSKyle Evans} 1759de0425eSKyle Evans 1764ad8b75dSGlen Barberarm_install_base() { 177*2af03ebfSMitchell Horne chroot ${CHROOTDIR} mount /dev/${mddev}${ROOTFSPART_SUFFIX} ${DESTDIR} 178c511a5abSGlen Barber _OSVERSION=$(chroot ${CHROOTDIR} /usr/bin/uname -U) 179c511a5abSGlen Barber REVISION=$(chroot ${CHROOTDIR} make -C /usr/src/release -V REVISION) 180c511a5abSGlen Barber BRANCH=$(chroot ${CHROOTDIR} make -C /usr/src/release -V BRANCH) 181c511a5abSGlen Barber export UNAME_r=${REVISION}-${BRANCH} 18204b7fd00SGlen Barber eval chroot ${CHROOTDIR} make -C ${WORLDDIR} \ 18304b7fd00SGlen Barber TARGET=${EMBEDDED_TARGET} \ 1844ad8b75dSGlen Barber TARGET_ARCH=${EMBEDDED_TARGET_ARCH} \ 1854ad8b75dSGlen Barber DESTDIR=${DESTDIR} KERNCONF=${KERNEL} \ 186c1f64992SGlen Barber ${CONF_FILES} installworld installkernel distribution 1872c26d77dSNathan Whitehorn chroot ${CHROOTDIR} mkdir -p ${DESTDIR}/boot/efi 18862a7dae4SWarner Losh # Compatibility symlink to /boot/msdos for 13.1 and earlier 1891be88beaSWarner Losh chroot ${CHROOTDIR} ln -s efi ${DESTDIR}/boot/msdos 1904ad8b75dSGlen Barber 191f3ca4d91SGlen Barber arm_create_user 1924fe984fdSEdward Tomasz Napierala arm_setup_usb_otg 193a8d0ee75SEmmanuel Vadot arm64_setup_multicons 19466e38012SEmmanuel Vadot arm_setup_fdt_overlays 1959de0425eSKyle Evans arm_setup_minimal_loader 1969848333bSEmmanuel Vadot arm_do_quirk 19788feae84SGlen Barber 1984ad8b75dSGlen Barber echo '# Custom /etc/fstab for FreeBSD embedded images' \ 19904b7fd00SGlen Barber > ${CHROOTDIR}/${DESTDIR}/etc/fstab 20038e4df10SEmmanuel Vadot echo "/dev/ufs/rootfs / ufs rw 1 1" \ 20138e4df10SEmmanuel Vadot >> ${CHROOTDIR}/${DESTDIR}/etc/fstab 20245d0192eSEmmanuel Vadot echo "/dev/msdosfs/EFI /boot/efi msdosfs rw,noatime 0 0" \ 20338e4df10SEmmanuel Vadot >> ${CHROOTDIR}/${DESTDIR}/etc/fstab 2045bffdafdSDaniel Engerg echo "tmpfs /tmp tmpfs rw,mode=1777 0 0" \ 20504b7fd00SGlen Barber >> ${CHROOTDIR}/${DESTDIR}/etc/fstab 2064ad8b75dSGlen Barber 2074ad8b75dSGlen Barber local hostname 2084ad8b75dSGlen Barber hostname="$(echo ${KERNEL} | tr '[:upper:]' '[:lower:]')" 20904b7fd00SGlen Barber echo "hostname=\"${hostname}\"" > ${CHROOTDIR}/${DESTDIR}/etc/rc.conf 21057228a49SJoerg Wunsch echo 'ifconfig_DEFAULT="DHCP inet6 accept_rtadv"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf 21104b7fd00SGlen Barber echo 'sshd_enable="YES"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf 21204b7fd00SGlen Barber echo 'sendmail_enable="NONE"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf 21304b7fd00SGlen Barber echo 'sendmail_submit_enable="NO"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf 21404b7fd00SGlen Barber echo 'sendmail_outbound_enable="NO"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf 21504b7fd00SGlen Barber echo 'sendmail_msp_queue_enable="NO"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf 21660bc17f4SGlen Barber echo 'growfs_enable="YES"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf 2174347ef60SMike Karels if [ -n "${CONFIG_POWERD_ENABLE}" ]; then 2184347ef60SMike Karels echo 'powerd_enable="YES"' >> ${CHROOTDIR}/${DESTDIR}/etc/rc.conf 2194347ef60SMike Karels fi 2204ad8b75dSGlen Barber 2214ad8b75dSGlen Barber sync 22204b7fd00SGlen Barber umount_loop ${CHROOTDIR}/${DESTDIR} 2234ad8b75dSGlen Barber 2244ad8b75dSGlen Barber return 0 2254ad8b75dSGlen Barber} 2264ad8b75dSGlen Barber 22743e289dfSEmmanuel Vadotarm_install_boot() { 22843e289dfSEmmanuel Vadot FATMOUNT="${DESTDIR%${KERNEL}}/fat" 22943e289dfSEmmanuel Vadot UFSMOUNT="${DESTDIR%${KERNEL}}/ufs" 23043e289dfSEmmanuel Vadot chroot ${CHROOTDIR} mkdir -p "${FATMOUNT}" "${UFSMOUNT}" 231*2af03ebfSMitchell Horne dospart="/dev/${mddev}${EFIPART_SUFFIX}" 232*2af03ebfSMitchell Horne ufspart="/dev/${mddev}${ROOTFSPART_SUFFIX}" 23338e4df10SEmmanuel Vadot 23438e4df10SEmmanuel Vadot chroot ${CHROOTDIR} mount_msdosfs ${dospart} ${FATMOUNT} 23538e4df10SEmmanuel Vadot chroot ${CHROOTDIR} mount ${ufspart} ${UFSMOUNT} 23643e289dfSEmmanuel Vadot 23743e289dfSEmmanuel Vadot BOOTFILES="$(chroot ${CHROOTDIR} \ 23843e289dfSEmmanuel Vadot env TARGET=${EMBEDDED_TARGET} TARGET_ARCH=${EMBEDDED_TARGET_ARCH} \ 23943e289dfSEmmanuel Vadot WITH_UNIFIED_OBJDIR=yes \ 24043e289dfSEmmanuel Vadot make -C ${WORLDDIR}/stand -V .OBJDIR)" 24143e289dfSEmmanuel Vadot BOOTFILES="$(chroot ${CHROOTDIR} realpath ${BOOTFILES})" 24243e289dfSEmmanuel Vadot 24343e289dfSEmmanuel Vadot chroot ${CHROOTDIR} mkdir -p ${FATMOUNT}/EFI/BOOT 2443e6e16b4SWarner Losh chroot ${CHROOTDIR} cp -p ${BOOTFILES}/efi/loader_lua/loader_lua.efi \ 24543e289dfSEmmanuel Vadot ${FATMOUNT}/EFI/BOOT/$(efi_boot_name ${EMBEDDED_TARGET}) 24643e289dfSEmmanuel Vadot 2477b7dbfa9SEmmanuel Vadot chroot ${CHROOTDIR} cp -R ${UFSMOUNT}/boot/dtb ${FATMOUNT} 2487b7dbfa9SEmmanuel Vadot 24943e289dfSEmmanuel Vadot chroot ${CHROOTDIR} touch ${UFSMOUNT}/firstboot 25043e289dfSEmmanuel Vadot sync 25143e289dfSEmmanuel Vadot umount_loop ${CHROOTDIR}/${FATMOUNT} 25243e289dfSEmmanuel Vadot umount_loop ${CHROOTDIR}/${UFSMOUNT} 25343e289dfSEmmanuel Vadot chroot ${CHROOTDIR} rmdir ${FATMOUNT} 25443e289dfSEmmanuel Vadot chroot ${CHROOTDIR} rmdir ${UFSMOUNT} 25543e289dfSEmmanuel Vadot} 25643e289dfSEmmanuel Vadot 2574ad8b75dSGlen Barberarm_install_uboot() { 25886635d49SMitchell Horne # Override in the ${EMBEDDED_TARGET}/${BOARDNAME}.conf file. 2594ad8b75dSGlen Barber 2604ad8b75dSGlen Barber return 0 2614ad8b75dSGlen Barber} 2629848333bSEmmanuel Vadot 2639848333bSEmmanuel Vadotarm_do_quirk() { 26486635d49SMitchell Horne # Override in the ${EMBEDDED_TARGET}/${BOARDNAME}.conf file. 2659848333bSEmmanuel Vadot} 266*2af03ebfSMitchell Horne 267*2af03ebfSMitchell Hornearm_create_partitions() { 268*2af03ebfSMitchell Horne # Override in the ${EMBEDDED_TARGET}/${BOARDNAME}.conf file. 269*2af03ebfSMitchell Horne 270*2af03ebfSMitchell Horne # Set defaults for EFIPART_SUFFIX, ROOTFSPART_SUFFIX, and 271*2af03ebfSMitchell Horne # BSDLABEL_SUFFIX (MBR only), needed elsewhere. 272*2af03ebfSMitchell Horne 273*2af03ebfSMitchell Horne if [ "${PART_SCHEME}" = "GPT" ]; then 274*2af03ebfSMitchell Horne export EFIPART_SUFFIX=p1 275*2af03ebfSMitchell Horne export ROOTFSPART_SUFFIX=p2 276*2af03ebfSMitchell Horne fi 277*2af03ebfSMitchell Horne if [ "${PART_SCHEME}" = "MBR" ]; then 278*2af03ebfSMitchell Horne export EFIPART_SUFFIX=s1 279*2af03ebfSMitchell Horne export BSDLABEL_SUFFIX=s2 280*2af03ebfSMitchell Horne export ROOTFSPART_SUFFIX=s2a 281*2af03ebfSMitchell Horne fi 282*2af03ebfSMitchell Horne} 283