SpectreOS-old/make_mksquashfs-auto.sh

475 lines
16 KiB
Bash
Raw Normal View History

2018-02-26 02:41:29 +01:00
#!/bin/bash
#
set -ex
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root" 1>&2
2018-04-07 19:07:06 +02:00
sudo "$0" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
2018-02-26 02:41:29 +01:00
exit 0
fi
2018-04-21 03:29:50 +02:00
# full parameters
2018-05-10 07:01:12 +02:00
# ./make_mksquashfs-auto.sh xfce4 deletework deletecache makesystem mkinitcpio filesystem initcheck makeimage makebios makeiso
2018-04-21 03:29:50 +02:00
2018-02-26 02:41:29 +01:00
iso_name=spectre_os
iso_label="SPECTRE_OS"
iso_version=$(date +%Y.%m.%d)
out_dir=out
install_dir=arch
version="$1"
2018-04-25 09:21:00 +02:00
shift
2018-04-21 03:29:50 +02:00
2018-04-21 22:19:39 +02:00
echo "Hallo Echo"
2018-04-21 03:29:50 +02:00
# for-schleife
2018-04-25 09:21:00 +02:00
for wort in "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
2018-04-25 08:09:12 +02:00
do
2018-04-21 03:29:50 +02:00
echo "$wort"
2018-04-23 13:56:36 +02:00
if [ "$wort" == "deletework" ]; then deletework=y; fi
2018-05-10 07:01:12 +02:00
if [ "$wort" == "deletecache" ]; then deletecache=y; fi
2018-04-25 09:28:05 +02:00
if [ "$wort" == "makesystem" ]; then makesystem=y; fi
if [ "$wort" == "mkinitcpio" ]; then mkinitcpio=y; fi
2018-04-23 13:56:36 +02:00
if [ "$wort" == "filesystem" ]; then filesystem=y; fi
2018-04-25 18:44:38 +02:00
if [ "$wort" == "initcheck" ]; then initcheck=y; fi
2018-04-23 13:56:36 +02:00
if [ "$wort" == "makeimage" ]; then makeimage=y; fi
2018-04-25 09:28:05 +02:00
if [ "$wort" == "makebios" ]; then makebios=y; fi
2018-04-23 13:56:36 +02:00
if [ "$wort" == "makeiso" ]; then makeiso=y; fi
2018-04-21 03:29:50 +02:00
done
sleep 5
2018-02-26 02:41:29 +01:00
arch=$(uname -m)
[[ -z "${version}" ]] && version="voll"
2018-04-08 20:07:02 +02:00
hostname="SpectreOS-${version}"
2018-03-10 19:10:35 +01:00
work_dir="${version}"
2018-02-26 02:41:29 +01:00
if [ "${version}" == "libre" ]; then
linuxparameter="-libre"
fi
function minimalinstallation() {
2018-06-01 23:37:01 +02:00
pacman -S $(cat base.txt) --needed --ignore linux
2018-02-26 02:41:29 +01:00
cp mirrorlist* /etc/pacman.d/
2018-05-04 22:43:57 +02:00
2018-05-10 07:01:12 +02:00
if [ "${deletecache}" == "y" ]; then
2018-05-04 22:43:57 +02:00
pacman -Scc <<EOT
2018-05-03 19:46:36 +02:00
j
j
EOT
2018-05-04 22:43:57 +02:00
pacman -Syy
fi
2018-02-26 02:41:29 +01:00
if [ "${version}" == "libre" ]; then
2018-05-26 01:42:05 +02:00
cp pacman.conf_libre /etc/pacman.conf
2018-05-02 21:45:13 +02:00
pacman -U --noconfirm --force https://www.parabola.nu/packages/libre/any/parabola-keyring/download
2018-04-25 14:24:36 +02:00
./pacstrap -C pacman.conf_libre -c -d -G -M ${work_dir}/${arch}/airootfs $(cat base_libre.txt)
2018-05-02 21:19:28 +02:00
elif [ "${version}" == "manjaro" ]; then
2018-05-26 01:42:05 +02:00
cp pacman.conf_manjaro /etc/pacman.conf
2018-05-02 21:45:13 +02:00
pacman -U --noconfirm --force https://mirror.philpot.de/manjaro/stable/core/x86_64/manjaro-keyring-20171027-2-any.pkg.tar.xz
2018-05-21 19:33:16 +02:00
./pacstrap -C pacman.conf_manjaro -c -d -G -M ${work_dir}/${arch}/airootfs $(cat base.txt)
2018-02-26 02:41:29 +01:00
else
2018-05-26 01:42:05 +02:00
cp pacman.conf /etc/pacman.conf
2018-04-25 14:24:36 +02:00
./pacstrap -C pacman.conf -c -d -G -M ${work_dir}/${arch}/airootfs $(cat base.txt)
2018-02-26 02:41:29 +01:00
fi
}
function secureumount() {
#statements
#
if cat /proc/mounts | grep ${device}1 > /dev/null; then
echo "gemountet"
umount ${device}1
else
echo "nicht gemountet"
fi
#
if cat /proc/mounts | grep ${device}2 > /dev/null; then
echo "gemountet"
umount ${device}2
else
echo "nicht gemountet"
fi
#
if cat /proc/mounts | grep ${device}3 > /dev/null; then
echo "gemountet"
umount ${device}3
else
echo "nicht gemountet"
fi
#
}
2018-04-25 08:40:34 +02:00
function system() {
2018-02-26 02:41:29 +01:00
if [ "$system" != "n" ]
then
if [ "$pacstrap" != "n" ]
then
if [ "$pacstrap" != "debug" ]; then
2018-04-21 03:29:50 +02:00
if [ "${deletework}" == "y" ]; then
2018-02-26 02:41:29 +01:00
if [ -d ${work_dir} ]; then
echo "delete work"
sleep 5
rm -Rv ${work_dir}
fi
fi
2018-04-25 09:28:05 +02:00
if [ "${makesystem}" == "y" ]; then
2018-04-25 10:54:48 +02:00
mkdir -p ${work_dir}/${arch}/airootfs
minimalinstallation
2018-04-25 09:28:05 +02:00
fi
2018-02-26 02:41:29 +01:00
fi
fi
2018-04-25 08:09:12 +02:00
if [ "${mkinitcpio}" == "y" ]; then
# module and hooks
2018-04-25 09:28:05 +02:00
# hooks
cp -v install/archiso* ${work_dir}/${arch}/airootfs/usr/lib/initcpio/install/
cp -v hooks/archiso* ${work_dir}/${arch}/airootfs/usr/lib/initcpio/hooks/
cp -v script/archiso* ${work_dir}/${arch}/airootfs/usr/lib/initcpio/
cp -v install/cow_device ${work_dir}/${arch}/airootfs/usr/lib/initcpio/install/
cp -v hooks/cow_device ${work_dir}/${arch}/airootfs/usr/lib/initcpio/hooks/
2018-04-25 10:54:48 +02:00
# modprobe.d
mkdir -p ${work_dir}/${arch}/airootfs/etc/modprobe.d/
echo "blacklist floppy" > ${work_dir}/${arch}/airootfs/etc/modprobe.d/blacklist-floppy.conf
echo "blacklist nouveau" > ${work_dir}/${arch}/airootfs/etc/modprobe.d/blacklist_nouveau.conf
2018-04-25 10:08:07 +02:00
2018-05-03 14:47:08 +02:00
if [ "${version}" == "libre" ] || [ "${version}" == "lite" ] || [ "${version}" == "manjaro" ]; then
2018-06-02 00:01:15 +02:00
echo "MODULES=\"nouveau i915 radeon ata_generic ata_piix nls_cp437 vfat ext4 btrfs\"" > ${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf
2018-05-15 18:17:29 +02:00
echo "HOOKS=\"base udev archiso block filesystems keyboard plymouth\"" >> ${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf
2018-04-25 08:09:12 +02:00
echo "COMPRESSION=\"lz4\"" >> ${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf
echo "FILES=\"/etc/modprobe.d/blacklist-floppy.conf\"" >> ${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf
else
2018-05-15 18:17:29 +02:00
echo "MODULES=\"nvidia nvidia_modeset nvidia_uvm nvidia_drm i915 radeon ata_generic ata_piix nls_cp437 vfat ext4 btrfs\"" > ${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf
echo "HOOKS=\"base udev archiso block filesystems keyboard plymouth\"" >> ${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf
2018-04-25 08:09:12 +02:00
echo "COMPRESSION=\"lz4\"" >> ${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf
echo "FILES=\"/etc/modprobe.d/blacklist-floppy.conf /etc/modprobe.d/blacklist_nouveau.conf\"" >> ${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf
2018-04-02 04:44:41 +02:00
2018-04-25 08:09:12 +02:00
fi
fi
2018-02-26 02:41:29 +01:00
fi
}
function IMAGE() {
if [ "$image" != "n" ]
then
2018-03-05 07:48:12 +01:00
echo "System wird gereinigt und komprimiert!!!"
sleep 5
2018-02-26 02:41:29 +01:00
mkdir -p ${work_dir}/iso/${install_dir}/${arch}/airootfs/
2018-05-26 02:16:03 +02:00
./arch-chroot ${work_dir}/${arch}/airootfs /bin/bash <<EOT
2018-02-26 02:41:29 +01:00
pacman -Scc
j
j
pacman -Q > /pkglist.txt
EOT
cp ${work_dir}/${arch}/airootfs/pkglist.txt ${work_dir}/iso/${install_dir}/${arch}/
if [ -f ${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs ]
then
echo "${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs wird neu angelegt!!!"
rm ${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs
else
echo "airootfs.sfs nicht vorhanden!"
fi
mksquashfs ${work_dir}/${arch}/airootfs ${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs -comp xz -b 262144
sha512sum ${work_dir}/iso/${install_dir}/${arch}/airootfs.sfs > airootfs.sha512
sed s/"${work_dir}\/iso\/${install_dir}\/${arch}\/airootfs.sfs"/"\/run\/archiso\/bootmnt\/${install_dir}\/${arch}\/airootfs.sfs"/g airootfs.sha512 > ${work_dir}/iso/${install_dir}/${arch}/airootfs.sha512
else
echo "Image wird nicht neu aufgebaut!!!"
fi
}
function BIOS() {
if [ "$bios" != "n" ]
then
mkdir -p ${work_dir}/iso/isolinux
mkdir -p ${work_dir}/iso/${install_dir}/${arch}
mkdir -p ${work_dir}/iso/${install_dir}/boot/${arch}
mkdir -p ${work_dir}/iso/${install_dir}/boot/syslinux
cp -R ${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/* ${work_dir}/iso/${install_dir}/boot/syslinux/
2018-04-02 04:44:41 +02:00
2018-05-03 15:35:31 +02:00
if [ "${version}" == "manjaro" ]; then
2018-05-27 01:01:36 +02:00
cp $(echo $(find ${work_dir}/${arch}/airootfs/boot/ -name "initramfs*$(uname -m).img") | cut -d" " -f2 ) ${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img
cp $(echo $(find ${work_dir}/${arch}/airootfs/boot/ -name "vmlinuz*$(uname -m)") | cut -d" " -f1 ) ${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz
2018-05-03 15:35:31 +02:00
else
cp ${work_dir}/${arch}/airootfs/boot/initramfs-linux${linuxparameter}.img ${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img
cp ${work_dir}/${arch}/airootfs/boot/vmlinuz-linux${linuxparameter} ${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz
fi
2018-04-02 04:44:41 +02:00
2018-02-26 02:41:29 +01:00
cp ${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/isolinux.bin ${work_dir}/iso/isolinux/
cp ${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/isohdpfx.bin ${work_dir}/iso/isolinux/
cp ${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/ldlinux.c32 ${work_dir}/iso/isolinux/
echo "DEFAULT menu.c32" > ${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg
echo "PROMPT 0" >> ${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg
echo "MENU TITLE ${iso_label}" >> ${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg
echo "TIMEOUT 300" >> ${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg
echo "" >> ${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg
2018-04-04 12:43:27 +02:00
if [ "${version}" != "voll" ]
2018-02-26 02:41:29 +01:00
then
sed "s|%ISO_LABEL%|${iso_label}|g;
s|%arch%|${arch}|g;
s|%INSTALL_DIR%|${install_dir}|g" syslinux-standart.cfg >> ${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg
else
sed "s|%ISO_LABEL%|${iso_label}|g;
s|%arch%|${arch}|g;
s|%INSTALL_DIR%|${install_dir}|g" syslinux.cfg >> ${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg
fi
echo "" >> ${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg
echo "ONTIMEOUT arch" >> ${work_dir}/iso/${install_dir}/boot/syslinux/syslinux.cfg
echo "DEFAULT loadconfig" > ${work_dir}/iso/isolinux/isolinux.cfg
echo "" >> ${work_dir}/iso/isolinux/isolinux.cfg
echo "LABEL loadconfig" >> ${work_dir}/iso/isolinux/isolinux.cfg
echo " CONFIG /arch/boot/syslinux/syslinux.cfg" >> ${work_dir}/iso/isolinux/isolinux.cfg
echo " APPEND /arch/boot/syslinux/" >> ${work_dir}/iso/isolinux/isolinux.cfg
fi
}
function UEFI() {
if [ "$efi" != "n" ]
then
mkdir -p ${work_dir}/iso/EFI/archiso
mkdir -p ${work_dir}/iso/EFI/boot
mkdir -p ${work_dir}/iso/loader/entries
if [ -f ${work_dir}/iso/EFI/archiso/efiboot.img ]
then
rm ${work_dir}/iso/EFI/archiso/efiboot.img
else
echo "efiboot.img nicht vorhanden!"
fi
2018-04-25 08:40:34 +02:00
truncate -s 128M ${work_dir}/iso/EFI/archiso/efiboot.img
2018-02-26 02:41:29 +01:00
mkfs.vfat -n ${iso_label}_EFI ${work_dir}/iso/EFI/archiso/efiboot.img
mkdir -p ${work_dir}/efiboot
mount -t vfat -o loop ${work_dir}/iso/EFI/archiso/efiboot.img ${work_dir}/efiboot
mkdir -p ${work_dir}/efiboot/EFI/boot
mkdir -p ${work_dir}/efiboot/EFI/archiso
mkdir -p ${work_dir}/efiboot/loader/entries
cp ${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz ${work_dir}/efiboot/EFI/archiso/vmlinuz.efi
cp ${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img ${work_dir}/efiboot/EFI/archiso/archiso.img
2018-04-02 05:57:35 +02:00
#if [ "${version}" != "libre" ]; then
2018-04-25 08:09:12 +02:00
#cp ${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz-lts ${work_dir}/efiboot/EFI/archiso/vmlinuz-lts.efi
#cp ${work_dir}/iso/${install_dir}/boot/${arch}/archiso-lts.img ${work_dir}/efiboot/EFI/archiso/archiso-lts.img
2018-04-02 05:57:35 +02:00
#fi
2018-04-02 04:44:41 +02:00
2018-02-26 02:41:29 +01:00
cp ${work_dir}/${arch}/airootfs/usr/share/efitools/efi/PreLoader.efi ${work_dir}/efiboot/EFI/boot/bootx64.efi
cp ${work_dir}/${arch}/airootfs/usr/share/efitools/efi/HashTool.efi ${work_dir}/efiboot/EFI/boot/
cp ${work_dir}/${arch}/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi ${work_dir}/efiboot/EFI/boot/loader.efi
cp uefi-shell-v2-${arch}.conf ${work_dir}/efiboot/loader/entries/
cp uefi-shell-v1-${arch}.conf ${work_dir}/efiboot/loader/entries/
cp uefi-shell-v1-${arch}.conf ${work_dir}/iso/loader/entries/uefi-shell-v1-${arch}.conf
cp uefi-shell-v2-${arch}.conf ${work_dir}/iso/loader/entries/uefi-shell-v2-${arch}.conf
# EFI Shell 2.0 for UEFI 2.3+
if [ -f ${work_dir}/iso/EFI/shellx64_v2.efi ]
then
echo "Bereits Vorhanden!"
else
cp Shell.efi ${work_dir}/iso/EFI/shellx64_v2.efi
#curl -o ${work_dir}/iso/EFI/shellx64_v2.efi https://raw.githubusercontent.com/tianocore/edk2/master/ShellBinPkg/UefiShell/X64/Shell.efi
fi
# EFI Shell 1.0 for non UEFI 2.3+
if [ -f ${work_dir}/iso/EFI/shellx64_v1.efi ]
then
echo "Bereits Vorhanden!"
else
cp Shell_Full.efi ${work_dir}/iso/EFI/shellx64_v1.efi
#curl -o ${work_dir}/iso/EFI/shellx64_v1.efi https://raw.githubusercontent.com/tianocore/edk2/master/EdkShellBinPkg/FullShell/X64/Shell_Full.efi
fi
cp ${work_dir}/iso/EFI/shellx64_v2.efi ${work_dir}/efiboot/EFI/
cp ${work_dir}/iso/EFI/shellx64_v1.efi ${work_dir}/efiboot/EFI/
cp ${work_dir}/${arch}/airootfs/usr/share/efitools/efi/PreLoader.efi ${work_dir}/iso/EFI/boot/bootx64.efi
cp ${work_dir}/${arch}/airootfs/usr/share/efitools/efi/HashTool.efi ${work_dir}/iso/EFI/boot/
cp ${work_dir}/${arch}/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi ${work_dir}/iso/EFI/boot/loader.efi
echo "timeout 3" > ${work_dir}/iso/loader/loader.conf
echo "default archiso-${arch}-usb-default" >> ${work_dir}/iso/loader/loader.conf
echo "timeout 3" > ${work_dir}/efiboot/loader/loader.conf
echo "default archiso-${arch}-cd-default" >> ${work_dir}/efiboot/loader/loader.conf
for file in releng/archiso-x86_64-usb*
do
echo "$file"
sed "s|%ISO_LABEL%|${iso_label}|g;
s|%arch%|${arch}|g;
s|%INSTALL_DIR%|${install_dir}|g" $file > ${work_dir}/iso/loader/entries/${file##*/}
done
###
for file in releng/archiso-x86_64-cd*
do
echo "$file"
sed "s|%ISO_LABEL%|${iso_label}|g;
s|%arch%|${arch}|g;
s|%INSTALL_DIR%|${install_dir}|g" $file > ${work_dir}/efiboot/loader/entries/${file##*/}
done
2018-04-04 12:43:27 +02:00
if [ "${version}" == "voll" ]
2018-02-26 02:41:29 +01:00
then
for file in releng/all/archiso-x86_64-usb*
do
echo "$file"
sed "s|%ISO_LABEL%|${iso_label}|g;
s|%arch%|${arch}|g;
s|%INSTALL_DIR%|${install_dir}|g" $file > ${work_dir}/iso/loader/entries/${file##*/}
done
###
for file in releng/all/archiso-x86_64-cd*
do
echo "$file"
sed "s|%ISO_LABEL%|${iso_label}|g;
s|%arch%|${arch}|g;
s|%INSTALL_DIR%|${install_dir}|g" $file > ${work_dir}/efiboot/loader/entries/${file##*/}
done
fi
###
if [ "$trennen" != "n" ]
then
umount -d ${work_dir}/efiboot
fi
fi
}
function makeiso() {
if [ "$image" != "n" ]
then
imagename=arch-${iso_name}-${version}-${iso_version}-${arch}.iso
if [ "$run" != "n" ]
then
if [ -f ${out_dir}/${imagename} ]
then
rm ${out_dir}/${imagename}
fi
mkdir -p ${out_dir}
xorriso -as mkisofs \
-iso-level 3 \
-full-iso9660-filenames \
-volid "${iso_label}" \
-eltorito-boot isolinux/isolinux.bin \
-eltorito\-catalog isolinux/boot.cat \
-no-emul-boot -boot-load-size 4 -boot-info-table \
-isohybrid-mbr $(pwd)/${work_dir}/iso/isolinux/isohdpfx.bin \
-eltorito-alt-boot \
-e EFI/archiso/efiboot.img \
-no-emul-boot \
-isohybrid-gpt-basdat \
-output ${out_dir}/${imagename} ${work_dir}/iso/
fi
fi
}
2018-04-25 08:40:34 +02:00
system
2018-02-26 02:41:29 +01:00
2018-04-25 08:40:34 +02:00
if [ "${filesystem}" == "y" ]; then
2018-02-26 02:41:29 +01:00
2018-04-25 14:24:36 +02:00
echo ${hostname} > ${work_dir}/${arch}/airootfs/etc/hostname
2018-02-26 02:41:29 +01:00
cp arch-graphical-install-auto ${work_dir}/${arch}/airootfs/usr/bin/arch-graphical-install-auto
2018-04-25 14:24:36 +02:00
chmod +x ${work_dir}/${arch}/airootfs/usr/bin/arch-graphical-install-auto
./arch-chroot ${work_dir}/${arch}/airootfs /usr/bin/arch-graphical-install-auto ${version}
2018-04-25 18:28:57 +02:00
fi
if [ "${initcheck}" == "y" ]; then
2018-04-25 14:24:36 +02:00
echo "ERSTTSTART WIRD JETZT AUSGEFÜHRT"
echo "Der erste Start kann etwas länger dauern!!!"
echo "Bitte loggen sie sich mit root ein und fahren sie wieder mit poweroff runter!!!"
systemd-nspawn -b -D ${work_dir}/${arch}/airootfs
2018-02-26 02:41:29 +01:00
fi
2018-04-23 14:53:37 +02:00
if [ "${makeimage}" == "y" ]; then
2018-02-26 02:41:29 +01:00
# System-image
IMAGE
fi
2018-04-23 14:53:37 +02:00
if [ "${makebios}" == "y" ]; then
2018-04-25 08:09:12 +02:00
# BIOS
2018-02-26 02:41:29 +01:00
2018-04-25 08:09:12 +02:00
BIOS
2018-02-26 02:41:29 +01:00
2018-04-25 08:09:12 +02:00
# EFI
2018-02-26 02:41:29 +01:00
2018-04-25 08:09:12 +02:00
UEFI
2018-04-07 20:24:24 +02:00
fi
2018-02-26 02:41:29 +01:00
2018-04-23 14:53:37 +02:00
if [ "${makeiso}" == "y" ]; then
2018-04-25 08:09:12 +02:00
# MAKEISO
2018-02-26 02:41:29 +01:00
2018-04-25 08:09:12 +02:00
makeiso
2018-04-07 20:24:24 +02:00
fi
2018-02-26 02:41:29 +01:00
# chroot
echo "Fertig!!!"