#!/usr/bin/env bash
export LC_ALL=C

# Here the quick 'n dirty guide to adding a new OS to quickget
#
#  1. Update os_support() - add new OS, all lowercase
#  2. Update pretty_name() - add a pretty name for new OS *only if the catch all is not suitable*
#  3. Create a releases_newos() generator (required) outputs the current supported release versions
#  4. Create a editions_newos() generator (optional) outputs the editions if new OS has multiple flavours/editions
#  5. Update make_vm_config() - add any *required* new OS tweaks
#  6. Create a get_newos() function - that does something like this:
#     function get_newos() {
#         local EDITION="${1:-}"
#         local HASH=""
#         local ISO="newos-${RELEASE}-${EDITION}-amd64.iso"
#         local URL="https://www.newos.org/download/${RELEASE}/${EDITION}"
#
#         HASH=$(wget -q -O- "${URL}/SHA512SUMS" | grep "${ISO}" | cut -d' ' -f1)
#         echo "${URL}/${ISO} ${HASH}"
#     }

function cleanup() {
  if [ -n "$(jobs -p)" ]; then
    kill "$(jobs -p)"
  fi
}

function pretty_name() {
  local SIMPLE_NAME=""
  local PRETTY_NAME=""
  SIMPLE_NAME="${1}"
  case ${SIMPLE_NAME} in
    alma)               PRETTY_NAME="Alma Linux";;
    alpine)             PRETTY_NAME="Alpine Linux";;
    android)            PRETTY_NAME="Android x86";;
    archlinux)          PRETTY_NAME="Arch Linux";;
    archcraft)          PRETTY_NAME="Archcraft";;
    arcolinux)          PRETTY_NAME="Arco Linux";;
    blendos)            PRETTY_NAME="BlendOS";;
    cachyos)            PRETTY_NAME="CachyOS";;
    centos-stream)      PRETTY_NAME="CentOS Stream";;
    dragonflybsd)       PRETTY_NAME="DragonFlyBSD";;
    elementary)         PRETTY_NAME="elementary OS";;
    endeavouros)        PRETTY_NAME="EndeavourOS";;
    endless)            PRETTY_NAME="Endless OS";;
    freebsd)            PRETTY_NAME="FreeBSD";;
    freedos)            PRETTY_NAME="FreeDOS";;
    garuda)             PRETTY_NAME="Garuda Linux";;
    ghostbsd)           PRETTY_NAME="GhostBSD";;
    kdeneon)            PRETTY_NAME="KDE Neon";;
    kolibrios)          PRETTY_NAME="KolibriOS";;
    linuxmint)          PRETTY_NAME="Linux Mint";;
    lmde)               PRETTY_NAME="Linux Mint Debian Edition";;
    mageia)             PRETTY_NAME="Mageia";;
    mxlinux)            PRETTY_NAME="MX Linux";;
    netboot)            PRETTY_NAME="netboot.xyz";;
    netbsd)             PRETTY_NAME="NetBSD";;
    nixos)              PRETTY_NAME="NixOS";;
    macos)              PRETTY_NAME="macOS";;
    openbsd)            PRETTY_NAME="OpenBSD";;
    openindiana)        PRETTY_NAME="OpenIndiana";;
    opensuse)           PRETTY_NAME="openSUSE";;
    oraclelinux)        PRETTY_NAME="Oracle Linux";;
    popos)              PRETTY_NAME="Pop!_OS";;
    reactos)            PRETTY_NAME="ReactOS";;
    rebornos)           PRETTY_NAME="RebornOS";;
    rockylinux)         PRETTY_NAME="Rocky Linux";;
    holoiso)            PRETTY_NAME="HoloISO";;
    truenas-core)       PRETTY_NAME="TrueNAS Core";;
    truenas-scale)      PRETTY_NAME="TrueNAS Scale";;
    ubuntu-budgie)      PRETTY_NAME="Ubuntu Budgie";;
    ubuntucinnamon)     PRETTY_NAME="Ubuntu Cinnamon";;
    ubuntukylin)        PRETTY_NAME="Ubuntu Kylin";;
    ubuntu-mate)        PRETTY_NAME="Ubuntu MATE";;
    ubuntu-server)      PRETTY_NAME="Ubuntu Server";;
    ubuntustudio)       PRETTY_NAME="Ubuntu Studio";;
    ubuntu-unity)       PRETTY_NAME="Ubuntu Unity";;
    vanillaos)          PRETTY_NAME="Vanilla OS";;
    void)               PRETTY_NAME="Void Linux";;
    vxlinux)            PRETTY_NAME="VX Linux";;
    xerolinux)          PRETTY_NAME="XeroLinux";;
    zorin)              PRETTY_NAME="Zorin OS";;
    *)                  PRETTY_NAME="${SIMPLE_NAME^}";;
  esac
  echo "${PRETTY_NAME}"
}

function validate_release() {
  local DISPLAY_NAME=""
  local RELEASE_GENERATOR=""
  local RELEASES=""

  DISPLAY_NAME="$(pretty_name "${OS}")"
  case ${OS} in
    *ubuntu-server*) RELEASE_GENERATOR="releases_ubuntu-server";;
    *ubuntu*) RELEASE_GENERATOR="releases_ubuntu";;
    *) RELEASE_GENERATOR="${1}";;
  esac

  RELEASES=$(${RELEASE_GENERATOR})
  if [[ "${RELEASES}" != *"${RELEASE}"* ]]; then
      echo -e "ERROR! ${DISPLAY_NAME} ${RELEASE} is not a supported release.\n"
      echo -n "${RELEASES}"
      exit 1
  fi
}

function list_json() {
  # Reference: https://stackoverflow.com/a/67359273
  list_csv | jq -R 'split(",") as $h|reduce inputs as $in ([]; . += [$in|split(",")|. as $a|reduce range(0,length) as $i ({};.[$h[$i]]=$a[$i])])'
  exit 0
}

function list_csv() {
  local DISPLAY_NAME
  local DL=""
  local DOWNLOADER
  local FUNC
  local OPTION
  local OS
  local PNG
  local RELEASE
  local SVG
  local HAS_ZSYNC=0

  # Check if zsync is available
  if command -v zsync &>/dev/null; then
    HAS_ZSYNC=1
  fi

  if command -v aria2c &>/dev/null; then
    DL="aria2c"
  elif command -v wget &>/dev/null; then
    DL="wget"
  fi

  echo "Display Name,OS,Release,Option,Downloader,PNG,SVG"
  for OS in $(os_support); do
    DISPLAY_NAME="$(pretty_name "${OS}")"
    if [[ "${OS}" == *"ubuntu"* ]]; then
      FUNC="ubuntu"
    else
      FUNC="${OS}"
    fi
    PNG="https://quickemu-project.github.io/quickemu-icons/png/${FUNC}/${FUNC}-quickemu-white-pinkbg.png"
    SVG="https://quickemu-project.github.io/quickemu-icons/svg/${FUNC}/${FUNC}-quickemu-white-pinkbg.svg"

    for RELEASE in $("releases_${FUNC}"); do
      if [ "${OS}" == "macos" ]; then
        DOWNLOADER="macrecovery"
      elif [ "${OS}" == "ubuntu" ] && [ "${RELEASE}" == "daily-canary" ] && [ ${HAS_ZSYNC} -eq 1 ]; then
        DOWNLOADER="zsync"
      elif [ "${OS}" == "ubuntu" ] && [ "${RELEASE}" == "daily-legacy" ] && [ ${HAS_ZSYNC} -eq 1 ]; then
        DOWNLOADER="zsync"
      elif [[ "${OS}" == *"ubuntu"* ]] && [ "${RELEASE}" == "devel" ] && [ ${HAS_ZSYNC} -eq 1 ]; then
        DOWNLOADER="zsync"
      else
        DOWNLOADER="${DL}"
      fi

      # If the OS has an editions_() function, use it.
      if [[ $(type -t "editions_${OS}") == function ]]; then
        for OPTION in $(editions_"${OS}"); do
          echo "${DISPLAY_NAME},${OS},${RELEASE},${OPTION},${DOWNLOADER},${PNG},${SVG}"
        done
      elif [ "${OS}" == "windows" ]; then
        for OPTION in "${LANGS[@]}"; do
          echo "${DISPLAY_NAME},${OS},${RELEASE},${OPTION},${DOWNLOADER},${PNG},${SVG}"
        done
      else
        echo "${DISPLAY_NAME},${OS},${RELEASE},,${DOWNLOADER},${PNG},${SVG}"
      fi
    done
  done
  exit 0
}

function os_support() {
    echo alma \
    alpine \
    android \
    archlinux \
    archcraft \
    arcolinux \
    batocera \
    blendos \
    cachyos \
    centos-stream \
    debian \
    deepin \
    devuan \
    dragonflybsd \
    elementary \
    endeavouros \
    endless \
    fedora \
    freebsd \
    freedos \
    garuda \
    gentoo \
    ghostbsd \
    haiku \
    kali \
    kdeneon \
    kolibrios \
    kubuntu \
    linuxmint \
    lmde \
    mageia \
    manjaro \
    mxlinux \
    netboot \
    netbsd \
    nixos \
    lubuntu \
    macos \
    openbsd \
    openindiana \
    opensuse \
    oraclelinux \
    popos \
    reactos \
    rebornos \
    rockylinux \
    siduction \
    slackware \
    solus \
    holoiso \
    tails \
    truenas-core \
    truenas-scale \
    ubuntu \
    ubuntu-budgie \
    ubuntucinnamon \
    ubuntukylin \
    ubuntu-mate \
    ubuntu-server \
    ubuntustudio \
    ubuntu-unity \
    vanillaos \
    void \
    vxlinux \
    windows \
    xerolinux \
    xubuntu \
    zorin
}

function releases_alma() {
    echo 8.6 8.7 9.0 9.1
}

function editions_alma() {
    echo minimal dvd
}

function releases_alpine() {
    echo 3.12 3.13 3.14 3.15 latest
}

function releases_android() {
    echo 7.1 8.1 9.0
}

function editions_android() {
    echo x86 x86_64
}

function releases_archlinux() {
    echo latest
}

function releases_archcraft() {
    echo latest
}

function releases_arcolinux() {
    echo v21.09.11 v21.11.05 v22.01.10
}

function editions_arcolinux() {
    echo large small
}

function releases_blendos() {
    local RLIST
    RLIST=$(curl -s https://api.github.com/repos/blend-os/blendOS/releases  |grep tag_name | grep -o -E '[[:digit:]]+\.[[:digit:]]+' | tr ' \r\n' ' ')
    echo ${RLIST}

}

function editions_blendos() {
    echo gnome kde
}

function releases_cachyos() {
    echo 2300305
}

function editions_cachyos() {
    echo kde gnome
}

function releases_centos-stream() {
    echo 8 9
}

function editions_centos-stream() {
    echo dvd1 boot
}

function releases_debian() {
    DEBCURRENT=$(wget -q https://cdimage.debian.org/debian-cd/ -O- |grep '\.[0-9]/'|cut -d\> -f9|cut -d\/ -f1)
    local DEBOLD=$(wget -q https://cdimage.debian.org/cdimage/archive/ -O- |grep -e '>[1-9][0-9]\.'|grep -v 'live' | cut -d\> -f9|cut -d\/ -f1 )

    echo  ${DEBOLD} ${DEBCURRENT}
}

function editions_debian() {
    echo standard cinnamon gnome kde lxde lxqt mate xfce netinst
}

function releases_deepin() {
    echo 20 20.1 20.2 20.2.1 20.2.2 20.2.3 20.2.4 20.3 20.4 20.5 20.6 20.7
}

function releases_devuan() {
    echo beowulf chimaera
}

function releases_dragonflybsd() {
    # If you remove "".bz2" from the end of the searched URL, you will get only the current release - currently 6.4.0
    # We could add a variable so this behaviour is optional/switchable (maybe from option or env)
    DBSD_RELEASES=$(curl -sL  http://mirror-master.dragonflybsd.org/iso-images/| grep -E -o '\"dfly-x86_64-.*_REL.iso.bz2\"' | grep -o -E '[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+' )
    echo $DBSD_RELEASES
}

function releases_elementary() {
    echo 7.0
}

function releases_endeavouros() {
    echo apollo_22_1 \
    artemis-22_6 \
    artemis_neo_22_7 \
    artemis_neo_22_8 \
    artemis_nova_22_9 \
    atlantis-21_4 \
    atlantis_neo-21_5 \
    cassini_22_12
}

function releases_endless() {
  echo 5.0.0
}

function editions_endless() {
  echo base en fr pt_BR es
}

function releases_fedora() {
    echo 33 34 35 36 37 38
}

function releases_batocera() {
  echo 32 33 34
}

function editions_fedora() {
  echo Workstation \
  Budgie \
  Cinnamon \
  i3 \
  KDE \
  LXDE \
  LXQt \
  Mate \
  Xfce \
  Silverblue \
  Sericea \
  Kinoite \
  Sway \
  Server
}

function releases_freebsd(){
    local FBSD_RELEASES=$(curl -sL https://download.freebsd.org/ftp/releases/amd64/amd64/ISO-IMAGES/|grep -e 'class="link"' |grep -v '\.\.'|cut -d\" -f4|tr -d '/')
    echo ${FBSD_RELEASES}
}

function editions_freebsd(){
    echo disc1 dvd1
}

function releases_freedos() {
    echo 1.2 1.3
}

function releases_garuda() {
  echo latest
}

function editions_garuda() {
  URL="https://mirrors.fossho.st/garuda/iso/latest/garuda/"
  echo $(wget -q -O - ${URL} | grep '^<a href' | sed -e 's/^.*="//' -e 's/\/.*//')
}

function releases_gentoo() {
    echo latest
}

function releases_ghostbsd() {
    echo 21.10.16 21.11.24 22.01.12
}

function editions_ghostbsd() {
    echo mate xfce
}

function releases_haiku() {
    echo r1beta3 r1beta4
}

function editions_haiku() {
    echo x86_64 x86_gcc2h
}

function releases_kali() {
    echo current kali-weekly
}

function releases_kdeneon() {
    echo user testing unstable developer
}

function releases_kolibrios() {
    echo latest
}

function releases_linuxmint(){
    echo 20.2 20.3 21 21.1
}

function editions_linuxmint(){
    echo cinnamon mate xfce
}

function editions_lmde(){
    echo cinnamon
}

function releases_lmde(){
    echo 5
}

function releases_mageia(){
    echo 8
}

function editions_mageia(){
    echo Plasma GNOME Xfce
}

function releases_mxlinux(){
    echo 21.3
}

function editions_mxlinux(){
    echo Xfce KDE Fluxbox
}

function releases_macos() {
    echo high-sierra mojave catalina big-sur monterey ventura
}

function releases_manjaro() {
    echo xfce \
    gnome \
    kde \
    budgie \
    cinnamon \
    i3 \
    mate
}

function releases_netboot() {
  echo latest
}

function releases_netbsd() {
    local NBSD_RELEASES=$(curl -sL  http://cdn.netbsd.org/pub/NetBSD/iso/ | grep -o -E '\"[[:digit:]]+\.[[:digit:]]+/\"' |tr -d '"/' |sort -nr )
    echo ${NBSD_RELEASES}
}

function releases_nixos(){
    echo 21.05 21.11 22.05 22.11 23.05
}

function editions_nixos(){
    echo gnome plasma5 minimal
}

function releases_openbsd(){
    local OBSD_RELEASES=$(curl -sL https://mirror.leaseweb.com/pub/OpenBSD/|grep -e '6\.[8-9]/' -e '[7-9]\.'|cut -d\" -f4|tr -d '/')
    echo ${OBSD_RELEASES}
}

function releases_openindiana(){
    echo 20230421
}

function editions_openindiana(){
    echo gui text minimal
}

function releases_opensuse(){
    echo 15.0 15.1 15.2 15.3 15.4 microos tumbleweed
}

function releases_oraclelinux() {
    echo 7.7 7.8 7.9 8.4 8.5 8.6 9.0
}

function releases_popos() {
    echo 20.04 21.10 22.04
}

function editions_popos() {
    echo intel nvidia
}

function releases_reactos() {
    echo latest
}

function releases_rebornos() {
    echo latest
}

function get_rebornos() {
   local ISO=$(curl -s 'https://www.rebornos.org/download/' | grep -ohE 'https://pub-cb7a4d4f7a974896b3bf40c52d1defbc.r2.dev/RebornOS-ISO/(rebornos_xfce_minimal|rebornos_iso)-[0-9]{4}.[0-9]{2}.[0-9]{2}-x86_64.iso' | tail -n1)
   local HASH=$(curl -s 'https://www.rebornos.org/download/' | grep -ozP 'Checksum MD5:.*[0-9a-fA-F]{32}' | grep -zoP '[0-9a-fA-F]{32}' | cut -d '' -f1)
   echo "${ISO} ${HASH}"
}

function releases_rockylinux() {
    echo 8.3 8.4 8.5 8.6 8.7 9.0 9.1
}

function editions_rockylinux() {
    echo minimal dvd boot
}

function releases_siduction() {
    echo latest
}

function editions_siduction() {
    echo kde lxqt nox xfce xorg
}

function releases_slackware() {
    echo 14.2 15.0
}

function releases_solus() {
    echo 4.3
}

function editions_solus() {
    echo Budgie GNOME MATE Plasma
}

function releases_holoiso() {
    echo 4.0
}

function releases_tails() {
    echo stable
}

function releases_truenas() {
  if [[ $OS == truenas ]] ; then
    echo "ERROR! The supported TrueNAS OS values are truenas-core or truenas-scale"
    exit 1;
  fi
  }

function releases_truenas-core() {
   echo 12.0 13.0
}

function releases_truenas-scale() {
    echo 22.02 22.12
}

function releases_ubuntu() {
    local LTS_SUPPORT="14.04 16.04 18.04 20.04 22.04"
    local INTERIM_SUPPORT="22.10 23.04"

    case "${OS}" in
        kubuntu|lubuntu|ubuntukylin|\
        ubuntu-mate|ubuntustudio|xubuntu)
        ## after 14.04
        LTS_SUPPORT="${LTS_SUPPORT/14.04 /}"
        ;;
        ubuntu-budgie)
        #after 16.04
        LTS_SUPPORT="${LTS_SUPPORT/14.04 16.04 /}"
        ;;
        ubuntu-unity)
        INTERIM_SUPPORT="${INTERIM_SUPPORT}"
        ;;
        ubuntucinnamon)
        INTERIM_SUPPORT="${INTERIM_SUPPORT/22.10 /}"
        ;;
    esac


    if [ "${OS}" == "ubuntu-unity" ]  ||  [ "${OS}" == "ubuntucinnamon" ]; then
        echo ${INTERIM_SUPPORT} \
            daily-live \
            daily-canary \
             ;

    else
        echo ${LTS_SUPPORT} \
            ${INTERIM_SUPPORT} \
            jammy-daily \
            daily-live \
            daily-canary \
            daily-legacy \
            eol-4.10 \
            eol-5.04 \
            eol-5.10 \
            eol-6.06.0 eol-6.06.1 eol-6.06.2 \
            eol-6.10 \
            eol-7.04 \
            eol-7.10 \
            eol-8.04.0 eol-8.04.1 eol-8.04.2 eol-8.04.3 eol-8.04.4 \
            eol-8.10 \
            eol-9.04 \
            eol-9.10 \
            eol-10.04.0 eol-10.04.1 eol-10.04.2 eol-10.04.3 eol-10.04.4 \
            eol-10.10 \
            eol-11.04 \
            eol-11.10 \
            eol-12.04 eol-12.04.0 eol-12.04.1 eol-12.04.2 eol-12.04.3 eol-12.04.4 eol-12.04.5 \
            eol-12.10 \
            eol-13.04 \
            eol-13.10 \
            eol-14.04.0 eol-14.04.1 eol-14.04.2 eol-14.04.3 eol-14.04.4 eol-14.04.5 \
            eol-14.10 \
            eol-15.04 \
            eol-15.10 \
            eol-16.04.0 eol-16.04.1 eol-16.04.2 eol-16.04.3 eol-16.04.4 eol-16.04.5 eol-16.04.6 \
            eol-16.10 \
            eol-17.04 \
            eol-17.10 \
            eol-18.04 eol-18.04.0 eol-18.04.1 eol-18.04.2 eol-18.04.3 eol-18.04.4 eol-18.04.5 \
            eol-18.10 \
            eol-19.04 \
            eol-19.10 \
            eol-20.04 eol-20.04.0 eol-20.04.1 eol-20.04.2 \
            eol-20.10 \
            eol-21.04 \
            eol-21.10 \
            ;
    fi
}

function releases_ubuntu-server() {
   local LTS_SUPPORT="18.04 20.04 22.04"
   local INTERIM_SUPPORT="22.10 23.04"
    echo ${LTS_SUPPORT} \
         ${INTERIM_SUPPORT} \
         daily-live
}

function releases_vanillaos() {
    echo 22.10
}

function releases_void() {
    echo current
}

function editions_void() {
    echo glibc musl xfce-glibc xfce-musl
}

function releases_vxlinux() {
    echo 6.1.2 6.1 5.0 4.2 4.1 4.0
}

function releases_windows() {
    echo 10 11
}

function releases_xerolinux() {
    echo kde
}

function releases_zorin() {
    echo 16
}

function editions_zorin() {
    echo core64 lite64 education64 edulite64
}

function check_hash() {
    local iso=""
    local hash=""
    local hash_algo=""
    iso="${VM_PATH}/${1}"
    hash="${2}"

    # Guess the hash algorithm by the hash length
    case ${#hash} in
      32) hash_algo=md5sum;;
      40) hash_algo=sha1sum;;
      64) hash_algo=sha256sum;;
      128) hash_algo=sha512sum;;
       *) echo "WARNING! Can't guess hash algorithm, not checking ${iso} hash."
          return;;
    esac

    echo -n "Checking ${iso} with ${hash_algo}... "
    if ! echo "${hash} ${iso}" | ${hash_algo} --check --status; then
        echo "ERROR!"
        echo "${iso} doesn't match ${hash}. Try running 'quickget' again."
        exit 1
    else
        echo "Good!"
    fi
}

function web_get() {
    local DIR="${2}"
    local FILE=""
    local URL="${1}"

    if [ -n "${3}" ]; then
        FILE="${3}"
    else
        FILE="${URL##*/}"
    fi

    if ! mkdir -p "${DIR}" 2>/dev/null; then
      echo "ERROR! Unable to create directory ${DIR}"
      exit 1
    fi

    if command -v aria2c &>/dev/null; then
        if ! aria2c --stderr -x16 --continue=true --summary-interval=0 --download-result=hide --console-log-level=error "${URL}" --dir "${DIR}" -o "${FILE}"; then
          echo #Necessary as aria2c in suppressed mode does not have new lines
          echo "ERROR! Failed to download ${URL} with aria2c. Try running 'quickget' again."
          exit 1
        fi
        echo #Necessary as aria2c in suppressed mode does not have new lines
    else
        if ! wget --quiet --continue --show-progress --progress=bar:force:noscroll "${URL}" -O "${DIR}/${FILE}"; then
          echo "ERROR! Failed to download ${URL} with wget. Try running 'quickget' again."
          exit 1
        fi
    fi
}

function zsync_get() {
    local DIR="${2}"
    local FILE="${1##*/}"
    local OUT=""
    local URL="${1}"

    if command -v zsync &>/dev/null; then
        if [ -n "${3}" ]; then
            OUT="${3}"
        else
            OUT="${FILE}"
        fi

        if ! mkdir -p "${DIR}" 2>/dev/null; then
          echo "ERROR! Unable to create directory ${DIR}"
          exit 1
        fi

        # Only force http for zsync - not earlier because we might fall through here
        if ! zsync "${URL/https/http}.zsync" -i "${DIR}/${OUT}" -o "${DIR}/${OUT}" 2>/dev/null; then
            echo "ERROR! Failed to download ${URL/https/http}.zsync"
            exit 1
        fi

        if [ -e "${DIR}/${OUT}.zs-old" ]; then
            rm "${DIR}/${OUT}.zs-old"
        fi
    else
        echo "INFO: zsync not found, falling back to wget/aria2c"
        if [ -n "${3}" ]; then
            web_get "${1}" "${2}" "${3}"
        else
            web_get "${1}" "${2}"
        fi
    fi
}

function make_vm_config() {
    local CONF_FILE=""
    local IMAGE_FILE=""
    local ISO_FILE=""
    local IMAGE_TYPE=""
    local GUEST=""
    local SEC_BOOT=""

    IMAGE_FILE="${1}"
    ISO_FILE="${2}"
    case "${OS}" in
        batocera)
            GUEST="batocera"
            IMAGE_TYPE="img";;
        dragonflybsd)
            GUEST="dragonflybsd"
            IMAGE_TYPE="iso";;
        freebsd|ghostbsd)
            GUEST="freebsd"
            IMAGE_TYPE="iso";;
        haiku)
            GUEST="haiku"
            IMAGE_TYPE="iso";;
        freedos)
            GUEST="freedos"
            IMAGE_TYPE="iso";;
        kolibrios)
            GUEST="kolibrios"
            IMAGE_TYPE="iso";;
        macos)
            GUEST="macos"
            IMAGE_TYPE="img";;
        netbsd)
            GUEST="netbsd"
            IMAGE_TYPE="iso";;
        openbsd)
            GUEST="openbsd"
            IMAGE_TYPE="iso";;
        openindiana)
            GUEST="solaris"
            IMAGE_TYPE="iso";;
        reactos)
            GUEST="reactos"
            IMAGE_TYPE="iso";;
        truenas*)
            GUEST="truenas"
            IMAGE_TYPE="iso";;
        windows)
            GUEST="windows"
            IMAGE_TYPE="iso";;
        *)
            GUEST="linux"
            IMAGE_TYPE="iso";;
    esac

    if [ -n "${EDITION}" ]; then
        CONF_FILE="${OS}-${RELEASE}-${EDITION}.conf"
    else
        CONF_FILE="${OS}-${RELEASE}.conf"
    fi

    if [ ! -e "${CONF_FILE}" ]; then
        echo "Making ${CONF_FILE}"
        cat << EOF > "${CONF_FILE}"
#!$(which quickemu) --vm
guest_os="${GUEST}"
disk_img="${VM_PATH}/disk.qcow2"
${IMAGE_TYPE}="${VM_PATH}/${IMAGE_FILE}"
EOF
        echo "Giving user execute permissions on ${CONF_FILE},"
        chmod u+x "${CONF_FILE}"
        if [ -n "${ISO_FILE}" ]; then
            echo "fixed_iso=\"${VM_PATH}/${ISO_FILE}\"" >> "${CONF_FILE}"
        fi

        # OS specific tweaks
        case ${OS} in
          alma|centos-stream|endless|nixos|oraclelinux|popos|rockylinux)
            echo "disk_size=\"32G\"" >> "${CONF_FILE}";;
          openindiana)
            echo "boot=\"legacy\"" >> "${CONF_FILE}"
            echo "disk_size=\"32G\"" >> "${CONF_FILE}";;
          batocera)
            echo "disk_size=\"8G\"" >> "${CONF_FILE}";;
          dragonflybsd|haiku|openbsd|netbsd|slackware|tails)
            echo "boot=\"legacy\"" >> "${CONF_FILE}";;
          deepin)
            echo "disk_size=\"64G\"" >> "${CONF_FILE}"
            echo "ram=\"4G\"" >> "${CONF_FILE}"
            ;;
          freedos)
            echo "boot=\"legacy\"" >> "${CONF_FILE}"
            echo "disk_size=\"4G\"" >> "${CONF_FILE}"
            echo "ram=\"256M\"" >> "${CONF_FILE}"
            ;;
          kolibrios)
            echo "boot=\"legacy\"" >> "${CONF_FILE}"
            echo "disk_size=\"2G\"" >> "${CONF_FILE}"
            echo "ram=\"128M\"" >> "${CONF_FILE}"
            ;;
          truenas-scale|truenas-core)
            echo "boot=\"legacy\"" >> "${CONF_FILE}"
           # the rest is non-functional
           # echo "bootdrive_size=\"5G\"" >> "${CONF_FILE}" # boot drive
           # echo "1stdrive_size=\"20G\"" >> "${CONF_FILE}" # for testing
           # echo "2nddrive_size=\"20G\"" >> "${CONF_FILE}" # again, for testing
            ;;
          ubuntu-server)
            # 22.04+ fails on LVM build if disk size is < 10G
            # 22.04.1 fails on auto-install if TPM is disabled
            echo "disk_size=\"10G\"" >> "${CONF_FILE}"
            echo "ram=\"4G\"" >> "${CONF_FILE}"
            if [[ "${RELEASE}" == *"22.04"* ]]; then
            echo "tpm=\"on\"" >> "${CONF_FILE}"
            fi
            ;;
          vanillaos)
          ## Minimum 50G for abroot
           echo "disk_size=\"64G\"" >> "${CONF_FILE}"
           ;;
          zorin)
            case  ${EDITION} in
              education64|edulite64)
                echo "disk_size=\"32G\"" >> "${CONF_FILE}";;
            esac
            ;;
          reactos)
            echo "boot=\"legacy\"" >> "${CONF_FILE}"
            echo "disk_size=\"12G\"" >> "${CONF_FILE}"
            echo "ram=\"2048M\"" >> "${CONF_FILE}"
            ;;
          macos)
            echo "macos_release=\"${RELEASE}\"" >> "${CONF_FILE}"
            # https://github.com/quickemu-project/quickemu/issues/438
            if [ "${RELEASE}" == "monterey" ]; then
                echo "cpu_cores=2" >> "${CONF_FILE}"
            fi
            ;;
        esac

        if [ "${OS}" == "ubuntu" ] && [[ ${RELEASE} == *"daily"*  ]]; then
        # wont install  lobster testing with less than 18GB
          echo "disk_size=\"32G\"" >> "${CONF_FILE}"
        fi
        # Enable TPM for Windows 11
        if [ "${OS}" == "windows" ] && [ "${RELEASE}" -ge 11 ]; then
            echo "tpm=\"on\"" >> "${CONF_FILE}"
            # Only force SecureBoot on for non-Debian/Ubuntu distros.
            if [ -e "/usr/share/OVMF/OVMF_CODE_4M.fd" ] && [ -e "/usr/share/OVMF/OVMF_VARS_4M.fd" ]; then
              SEC_BOOT="off"
            else
              SEC_BOOT="on"
            fi
            echo "secureboot=\"${SEC_BOOT}\"" >> "${CONF_FILE}"
        fi
    fi
    echo
    echo "To start your $(pretty_name "${OS}") virtual machine run:"
    echo "    quickemu --vm ${CONF_FILE}"
    echo
    exit 0
}

function get_alma() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO="AlmaLinux-${RELEASE}-x86_64-${EDITION}.iso"
    local URL="https://mirror.rackspace.com/almalinux/${RELEASE/beta-1/beta}/isos/x86_64/"
    HASH="$(wget -q -O- "${URL}/CHECKSUM" | grep "(${ISO}" | cut -d' ' -f4)"
    echo "${URL}/${ISO} ${HASH}"
}

function get_alpine() {
    local HASH=""
    local ISO=""
    local URL=""
    local VERSION=""

    case ${RELEASE} in
      latest) URL="https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/x86_64";;
      *) URL="https://dl-cdn.alpinelinux.org/alpine/v${RELEASE}/releases/x86_64";;
    esac
    VERSION=$(wget -qO- "${URL}/latest-releases.yaml" | awk '/"Xen"/{found=0} {if(found) print} /"Virtual"/{found=1}' | grep 'version:' | awk '{print $2}')
    ISO="alpine-virt-${VERSION}-x86_64.iso"
    HASH=$(wget -qO- "${URL}/latest-releases.yaml" | awk '/"Xen"/{found=0} {if(found) print} /"Virtual"/{found=1}' | grep 'sha256:' | awk '{print $2}')
    echo "${URL}/${ISO} ${HASH}"
}

function get_android() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO=""
    local JSON_ALL=""
    local JSON_REL=""
    local URL="https://mirrors.gigenet.com/OSDN/android-x86"

    JSON_ALL=$(wget -q -O- "https://www.fosshub.com/Android-x86-old.html" | grep "var settings =" | cut -d'=' -f2-)
    JSON_REL=$(echo "${JSON_ALL}" | jq --arg ver "${OS}-${EDITION}-${RELEASE}" 'first(.pool.f[] | select((.n | startswith($ver)) and (.n | endswith(".iso"))))')
    ISO=$(echo "${JSON_REL}" | jq -r .n)
    HASH=$(echo "${JSON_REL}" | jq -r .hash.sha256)
    # Traverse the directories to find the .iso location
    for DIR in $(wget -4 -q -O- "${URL}" | grep -o -E '[0-9]{5}' | sort -ur); do
        if wget -4 -q -O- "${URL}/${DIR}" | grep "${ISO}" &>/dev/null; then
            URL="${URL}/${DIR}"
            break
        fi
    done
    echo "${URL}/${ISO} ${HASH}"
}

function get_archlinux() {
    local HASH=""
    local ISO=""
    local URL="https://mirror.rackspace.com/archlinux"
    ISO=$(wget -q -O- "https://archlinux.org/releng/releases/json/" | jq -r '.releases[0].iso_url')
    HASH=$(wget -q -O- "https://archlinux.org/releng/releases/json/" | jq -r '.releases[0].sha1_sum')
    echo "${URL}/${ISO} ${HASH}"
}

function get_archcraft() {
    local HASH=""
    local URL=""
    local TMPURL=""

    TMPURL=$(wget -q -S -O- --max-redirect=0 "https://sourceforge.net/projects/archcraft/files/latest/download" 2>&1 | grep -i Location | cut -d' ' -f4)
    URL=${TMPURL%\?*}
    echo "${URL} ${HASH}"
}

function get_arcolinux() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO="arcolinux${EDITION:0:1}-${RELEASE}-x86_64.iso"
    local URL="https://ant.seedhost.eu/arcolinux/iso/${RELEASE}"
    HASH=$(wget -q -O- "${URL}/${ISO}.sha1" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_blendos() {
    local EDITION="${1:-}"
    local HASH=""
    local URL=""
    case ${RELEASE} in
      23.01)
        URL="$(curl -s https://api.github.com/repos/blend-os/blendOS/releases  |grep 'browser_download_url'|grep ${RELEASE} | grep -o '\"http.*\.iso\"'| cut -d\" -f 2| head -1)"
        HASH=$(curl -s "${URL}.sha256sum" | cut -d' ' -f1)
        ;;
      23.04)
        case ${EDITION} in
          gnome)
            TMPURL=$(wget -q -S -O- --max-redirect=0 "https://sourceforge.net/projects/blendos/files/23.04-1/${EDITION^^}/blendOS-2023.04.22-x86_64-${EDITION,,}.iso/download" 2>&1 | grep -i Location | cut -d' ' -f4)
            URL=${TMPURL%\?*}
            HASH=$(curl -s https://sourceforge.net/projects/blendos/files/${RELEASE}-1/${EDITION:-GNOME}/|grep  -o -E '\"sha1\":\".*\"'|cut -d\" -f4)
            ;;
          kde|plasma)
            local ED_DE="Plasma"
            TMPURL=$(wget -q -S -O- --max-redirect=0 "https://sourceforge.net/projects/blendos/files/23.04-1/${ED_DE^}/blendOS-2023.04.22-x86_64-${ED_DE,,}.iso/download" 2>&1 | grep -i Location | cut -d' ' -f4)
            URL=${TMPURL%\?*}
            HASH=$(curl -s https://sourceforge.net/projects/blendos/files/${RELEASE}-1/Plasma/|grep  -o -E '\"sha1\":\".*\"'|cut -d\" -f4)
            ;;
        esac
        ;;
    esac
    echo "${URL} ${HASH}"
}

function get_vanillaos() {
  # maybe use github api and dynamism for R2.0 but for 22.10 just
  # hit their CDN
  #
  # https://cdn.vanillaos.org/assets/ISO/22.10-r8/VanillaOS-22.10-all.20230226.md5.txt
  # https://cdn.vanillaos.org/assets/ISO/22.10-r8/VanillaOS-22.10-all.20230226.sha256.txt
    local HASH=$(curl -s "https://cdn.vanillaos.org/assets/ISO/22.10-r8/VanillaOS-22.10-all.20230226.sha256.txt" | cut -d' ' -f1)
    local URL="https://cdn.vanillaos.org/assets/ISO/22.10-r8/VanillaOS-22.10-all.20230226.iso"
    echo "${URL} ${HASH}"
}

function get_batocera() {
    local HASH=""
    local URL="https://mirrors.o2switch.fr/batocera/x86_64/stable/last"
    local ISO="$(curl -sl ${URL}/ | grep -e 'batocera.*img.gz'|cut -d\" -f2)"
    local CURRENT_RELEASE=$(echo "${ISO}"| cut -d\- -f3)


    case ${RELEASE} in
      ${CURRENT_RELEASE})  #Current release
         URL+=""
         ;;
      *)
         URL+="/archives/${RELEASE}"
         ISO="$(curl -sl ${URL}/ | grep -e 'batocera.*img.gz'|cut -d\" -f2)"
         ;; # non-current are here

    esac


    echo "${URL}/${ISO} ${HASH}"
}

function get_cachyos() {
    local HASH=""
    local ISO="cachyos-${EDITION}-linux-${RELEASE}.iso"
    local URL="https://mirror.cachyos.org/ISO/${EDITION}/${RELEASE}"
    HASH=$(wget -q -O- "${URL}/${ISO}.sha256" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_centos-stream() {
    local HASH=""
    local ISO=""
    case ${RELEASE} in
      8)
        ISO="CentOS-Stream-${RELEASE}-x86_64-latest-${EDITION}.iso"
        URL="https://mirrors.ocf.berkeley.edu/centos/8-stream/isos/x86_64"
        HASH=$(wget -q -O- ${URL}/CHECKSUM | grep "SHA256 (${ISO}" | cut -d' ' -f4)
        ;;
      9)
        ISO="CentOS-Stream-${RELEASE}-latest-x86_64-${EDITION}.iso"
        URL="https://mirrors.ocf.berkeley.edu/centos-stream/9-stream/BaseOS/x86_64/iso"
        HASH=$(wget -q -O- ${URL}/${ISO}.SHA256SUM | grep "SHA256 (${ISO}" | cut -d' ' -f4)
        ;;
    esac

    echo "${URL}/${ISO} ${HASH}"
}

function get_debian() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO="debian-live-${RELEASE}-amd64-${EDITION}.iso"
    local URL=""

    DEBCURRENT=$(wget -q https://cdimage.debian.org/debian-cd/ -O- |grep '\.[0-9]/'|cut -d\> -f9|cut -d\/ -f1)
   case ${RELEASE} in
      "${DEBCURRENT}") URL="https://cdimage.debian.org/debian-cd/${RELEASE}-live/amd64/iso-hybrid";;
      *)      URL="https://cdimage.debian.org/cdimage/archive/${RELEASE}-live/amd64/iso-hybrid/";;
    esac

    if [ "${EDITION}" == "netinst" ]; then
        URL="${URL/-live/}"
        URL="${URL/hybrid/cd}"
        ISO="${ISO/-live/}"
    fi

    HASH=$(wget -q -O- "${URL}/SHA512SUMS" | grep "${ISO}" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_deepin() {
    local HASH=""
    local EDITION=""
    local ISO="deepin-desktop-community-${RELEASE}-amd64.iso"
    # deepin-desktop-community-20.3-amd64.iso
    local URL="https://cdimage.deepin.com/releases/"${RELEASE}

    # fix iso name
    if [[ "${RELEASE}" == *"20" ]] ; then
      EDITION="1003"
      ISO="deepin-desktop-community-${EDITION}-amd64.iso"
    elif [[ "${RELEASE}" == *"20.1" ]]; then
      EDITION="1010"
      ISO="deepin-desktop-community-${EDITION}-amd64.iso"
    fi

    HASH=$(wget -q -O- "${URL}/SHA256SUMS" | grep "${ISO}" | cut -d' ' -f1)

    #echo "${URL}/${ISO} ${HASH}"
    web_get "${URL}/${ISO}" "${VM_PATH}"
    check_hash "${ISO}" "${HASH}"
    make_vm_config "${ISO}"
}

function get_devuan() {
    local HASH=""
    local ISO=""
    local URL="https://files.devuan.org/devuan_${RELEASE}/desktop-live"

    case ${RELEASE} in
      beowulf) ISO="devuan_${RELEASE}_3.1.1_amd64_desktop-live.iso";;
      chimaera) ISO="devuan_${RELEASE}_4.0.2_amd64_desktop-live.iso";;
    esac
    HASH=$(wget -q -O- "${URL}/SHASUMS.txt" | grep "${ISO}" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_dragonflybsd() {
    local HASH=""
    local ISO="dfly-x86_64-${RELEASE}_REL.iso.bz2"
    local URL="http://mirror-master.dragonflybsd.org/iso-images"

    HASH=$(wget -q -O- "${URL}/md5.txt" | grep "(${ISO})" | cut -d' ' -f4)
    echo "${URL}/${ISO} ${HASH}"
}

function get_elementary() {
    local HASH=""
    case ${RELEASE} in
      6.2)
        local ISO="elementaryos-${RELEASE}-stable.20211218-rc.iso"
        ;;
      7.0)
        local ISO="elementaryos-${RELEASE}-stable.20230129rc.iso"
        ;;
    esac
    local URL="https://ams3.dl.elementary.io/download"
    echo "${URL}/$(date +%s | base64)/${ISO} ${HASH}"
}

function get_endeavouros() {
    local HASH=""
    # Endeavour release names are Capitalized and our $RELEASE is forced to lowercase so we have to revert it
    local ISO="EndeavourOS_${RELEASE@u}.iso"
    local URL="https://github.com/endeavouros-team/ISO/releases/download/1-EndeavourOS-ISO-releases-archive"

    HASH=$(wget -q -O- "${URL}/${ISO}.sha512sum" | cut  -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_endless() {
    local HASH="" # No hash - there is a signature in .asc signed by
    #https://d1anzknqnc1kmb.cloudfront.net/eos-image-keyring.gpg
    # (4096R: CB50 0F7B C923 3FAD 32B4 E720 9E0C 1250 587A 279C)
    local FILE_TS=""
    # https://support.endlessos.org/en/installation/direct-download gives the info but computes the URLS in js
    # so parsing out the useful info is not happening tonight
    # Endless edition names are "base" for the small minimal one or the Language for the large full release
    # The isos are stamped as they are finished so ....
    case ${EDITION} in
      base)
          FILE_TS="230127-211122";;
        fr)
          FILE_TS="230127-213415";;
        en)
          FILE_TS="230127-212436";;
        es)
          FILE_TS="230127-212646";;
        pt_BR)
          FILE_TS="230127-220328";;
      esac

      URL="https://images-dl.endlessm.com/release/${RELEASE}/eos-amd64-amd64/${EDITION}"
      ISO="eos-eos${RELEASE:0:3}-amd64-amd64.${FILE_TS}.${EDITION}.iso"

      echo "${URL}/${ISO}"
}

function get_fedora() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO=""
    local JSON=""
    local URL=""
    local VARIANT=""

    case ${EDITION} in
      Server|Kinoite|Silverblue|Sericea|Workstation) VARIANT="${EDITION}";;
      *) VARIANT="Spins";;
    esac

    JSON=$(wget -q -O- "https://getfedora.org/releases.json" | jq '.[] | select(.variant=="'${VARIANT}'" and .subvariant=="'"${EDITION}"'" and .arch=="x86_64" and .version=="'"${RELEASE}"'")')
    URL=$(echo "${JSON}" | jq -r '.link' | head -n1)
    HASH=$(echo "${JSON}" | jq -r '.sha256' | head -n1)
    echo "${URL} ${HASH}"
}

function get_freebsd() {
    local EDITION="${1}"
    local HASH=""
    local ISO="FreeBSD-${RELEASE}-RELEASE-amd64-${EDITION}.iso"
    local URL="https://download.freebsd.org/ftp/releases/amd64/amd64/ISO-IMAGES/${RELEASE}"

    HASH=$(wget -q -O- "${URL}/CHECKSUM.SHA256-FreeBSD-${RELEASE}-RELEASE-amd64" | grep "${ISO}" | grep -v ".xz" | cut -d' ' -f4)
    echo "${URL}/${ISO} ${HASH}"
}

function get_freedos() {
    local HASH=""
    local ISO=""
    local URL="http://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/distributions/${RELEASE}/official"

    case ${RELEASE} in
        1.2)
          ISO="FD12CD.iso"
          HASH=$(wget -q -O- "${URL}/FD12.sha" | grep "${ISO}" | cut -d' ' -f1)
          ;;
        1.3)
          ISO="FD13-LiveCD.zip"
          HASH=$(wget -q -O- "${URL}/verify.txt" | grep -A 8 "sha256sum" | grep "${ISO}" | cut -d' ' -f1)
          ;;
    esac

    echo "${URL}/${ISO} ${HASH}"
}

function get_garuda() {
  local EDITION="${1:-}"
  local HASH=""
  local ISO=""
  local URL="https://mirrors.fossho.st/garuda/iso/latest/garuda/"

  ISO=${EDITION}/latest.iso

  HASH="$(wget -q -O- "${URL}/${ISO}.sha256" | cut -d' ' -f1)"
  echo "${URL}/${ISO} ${HASH}"
}

function get_gentoo() {
    local HASH=""
    local ISO=""
    local URL="https://mirror.bytemark.co.uk/gentoo/releases/amd64/autobuilds/"

    ISO=$(wget -q -O- "${URL}/${RELEASE}-iso.txt" | grep install | cut -d' ' -f1)
    HASH=$( wget -q -O- "${URL}/${ISO}.DIGESTS" | grep iso | grep -v CONTENTS | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_ghostbsd() {
    local EDITION="${1:-}"
    local ISO=""
    local URL="https://download.ghostbsd.org/releases/amd64/${RELEASE}"
    local HASH=""

    case ${EDITION} in
      mate) ISO="GhostBSD-${RELEASE}.iso";;
      xfce) ISO="GhostBSD-${RELEASE}-XFCE.iso";;
    esac
    HASH=$(wget -q -O- "${URL}/${ISO}.sha256" | grep "${ISO}" | cut -d' ' -f4)
    echo "${URL}/${ISO} ${HASH}"
}

function get_haiku() {
    local EDITION="${1:-}"
    local ISO="haiku-${RELEASE}-${EDITION}-anyboot.iso"
    # local URL="https://cdn.haiku-os.org/haiku-release/${RELEASE}" # domain gone
    local URL="http://mirror.rit.edu/haiku/${RELEASE}" # NY, USA
    # local URL="https://mirrors.tnonline.net/haiku/haiku-release/${RELEASE}" # Sweden
    # local URL="https://mirror.aarnet.edu.au/pub/haiku/${RELEASE}" # Aus

    HASH=$(wget -q -O- "${URL}/${ISO}.sha256" | grep "${ISO}" | cut -d' ' -f4)
    echo "${URL}/${ISO} ${HASH}"
}

function get_kali() {
    local HASH=""
    local ISO=""
    local URL="https://cdimage.kali.org/${RELEASE}"

    ISO=$(wget -q -O- "${URL}/?C=M;O=D" | grep -o ">kali-linux-.*-installer-amd64.iso" | head -n 1 | cut -c 2-)
    HASH=$(wget -q -O- "${URL}/SHA256SUMS" | grep -v torrent | grep "${ISO}" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_kdeneon() {
    local HASH=""
    local ISO=""
    local URL="https://files.kde.org/neon/images/${RELEASE}/current"

    ISO=$(wget -q -O- "${URL}/neon-${RELEASE}-current.sha256sum" | cut -d' ' -f3-)
    HASH=$(wget -q -O- "${URL}/neon-${RELEASE}-current.sha256sum" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_kolibrios() {
    local HASH=""
    local ISO="kolibri.iso"
    local URL="https://builds.kolibrios.org/eng"
    echo "${URL}/${ISO} ${HASH}"
}

function get_linuxmint() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO="linuxmint-${RELEASE}-${EDITION}-64bit.iso"
    local URL="https://mirror.bytemark.co.uk/linuxmint/stable/${RELEASE}"

    HASH=$(wget -q -O- "${URL}/sha256sum.txt" | grep "${ISO}" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_lmde() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO="lmde-${RELEASE}-${EDITION}-64bit.iso"
    local URL="https://mirror.bytemark.co.uk/linuxmint/debian"

    HASH=$(wget -q -O- "${URL}/sha256sum.txt" | grep "${ISO}" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_macos() {
    local BOARD_ID=""
    local CWD=""
    local MACRECOVERY=""
    local MLB="00000000000000000"
    local OS_TYPE="default"

    case ${RELEASE} in
        lion)           #10.7
            BOARD_ID="Mac-2E6FAB96566FE58C"
            MLB="00000000000F25Y00";;
        mountainlion)   #10.8
            BOARD_ID="Mac-7DF2A3B5E5D671ED"
            MLB="00000000000F65100";;
        mavericks)      #10.9
            BOARD_ID="Mac-F60DEB81FF30ACF6"
            MLB="00000000000FNN100";;
        yosemite)       #10.10
            BOARD_ID="Mac-E43C1C25D4880AD6"
            MLB="00000000000GDVW00";;
        elcapitan)      #10.11
            BOARD_ID="Mac-FFE5EF870D7BA81A"
            MLB="00000000000GQRX00";;
        sierra)         #10.12
            BOARD_ID="Mac-77F17D7DA9285301"
            MLB="00000000000J0DX00";;
        high-sierra)    #10.13
            BOARD_ID="Mac-BE088AF8C5EB4FA2"
            MLB="00000000000J80300";;
        mojave)         #10.14
            BOARD_ID="Mac-7BA5B2DFE22DDD8C"
            MLB="00000000000KXPG00";;
        catalina)       #10.15
            BOARD_ID="Mac-00BE6ED71E35EB86";;
        big-sur)        #11
            BOARD_ID="Mac-42FD25EABCABB274";;
        monterey)       #12
            BOARD_ID="Mac-E43C1C25D4880AD6";;
        ventura)        #13
            BOARD_ID="Mac-7BA5B2D9E42DDD94";;
        *) echo "ERROR! Unknown release: ${RELEASE}"
           releases_macos
           exit 1;;
    esac

    # Use a bundled macrecovery if possible
    CWD="$(dirname "${0}")"
    if [ -x "${CWD}/macrecovery" ]; then
        MACRECOVERY="${CWD}/macrecovery"
    elif [ -x /usr/bin/macrecovery ]; then
        MACRECOVERY="/usr/bin/macrecovery"
    else
        web_get "https://raw.githubusercontent.com/wimpysworld/quickemu/master/macrecovery" "${HOME}/.quickemu"
        MACRECOVERY="python3 ${HOME}/.quickemu/macrecovery"
    fi

    if [ -z "${MACRECOVERY}" ]; then
        echo "ERROR! Can not find a usable macrecovery."
        exit 1
    fi

    # Get firmware
    web_get "https://github.com/kholia/OSX-KVM/raw/master/OpenCore/OpenCore.qcow2" "${VM_PATH}"
    web_get "https://github.com/kholia/OSX-KVM/raw/master/OVMF_CODE.fd" "${VM_PATH}"
    if [ ! -e "${VM_PATH}/OVMF_VARS-1920x1080.fd" ]; then
        web_get "https://github.com/kholia/OSX-KVM/raw/master/OVMF_VARS-1920x1080.fd" "${VM_PATH}"
    fi

    if [ ! -e "${VM_PATH}/RecoveryImage.chunklist" ]; then
        echo "Downloading ${RELEASE}..."
        ${MACRECOVERY} \
            --board-id "${BOARD_ID}" \
            --mlb "${MLB}" \
            --os-type "${OS_TYPE}" \
            --basename RecoveryImage \
            --outdir "${VM_PATH}" \
            download
    fi

    if [ -e "${VM_PATH}/RecoveryImage.dmg" ] && [ ! -e "${VM_PATH}/RecoveryImage.img" ]; then
        echo "Converting RecoveryImage..."
        qemu-img convert "${VM_PATH}/RecoveryImage.dmg" -O raw "${VM_PATH}/RecoveryImage.img" 2>/dev/null
    fi

    make_vm_config RecoveryImage.img
}

function get_mageia() {
    local EDITION="${1:-}"
    local ISO=$(wget -q https://www.mageia.org/en/downloads/get/?q="Mageia-${RELEASE}-Live-${EDITION}-x86_64.iso" -O- | grep 'click here'| grep -o 'href=.*\.iso'|cut -d\" -f2)
    local HASH=$(wget -q -O- "${ISO}.sha512" | cut -d' ' -f1)
    echo "${ISO} ${HASH}"
}

function get_manjaro() {
    local HASH=""
    local ISO=""
    local MANIFESTURL=""
    local URL=""

    case ${RELEASE} in
      gnome|kde|xfce) MANIFESTURL="https://gitlab.manjaro.org/webpage/manjaro-homepage/-/raw/master/site/content/downloads/official/${RELEASE}.md";;
      budgie|cinnamon|deepin|i3|mate) MANIFESTURL="https://gitlab.manjaro.org/webpage/manjaro-homepage/-/raw/master/site/content/downloads/community/${RELEASE}.md";;
    esac

    URL="$(wget -qO- "${MANIFESTURL}" | grep "Download_x64 =" | cut -d'"' -f2)"
    HASH=$(wget -qO- "${MANIFESTURL}" | grep "Download_x64_Checksum =" | cut -d'"' -f2)
    echo "${URL} ${HASH}"
}

function get_mxlinux() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO=""
    local URL="https://sourceforge.net/projects/mx-linux/files/Final/${EDITION}"

    case ${EDITION} in
      Xfce) ISO="MX-${RELEASE}_x64.iso";;
      KDE) ISO="MX-${RELEASE}_KDE_x64.iso";;
      Fluxbox) ISO="MX-${RELEASE}_fluxbox_x64.iso";;
    esac
    HASH=$(wget -q -O- "${URL}/${ISO}.sha256" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_netboot() {
    local ISO="netboot.xyz.iso"
    local HASH=""
    local URL="https://boot.netboot.xyz/ipxe"
    HASH=$(wget -q -O- "${URL}/netboot.xyz-sha256-checksums.txt" | grep "${ISO}" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_netbsd() {
    local HASH=""
    local ISO="NetBSD-${RELEASE}-amd64.iso"
    local URL="https://cdn.netbsd.org/pub/NetBSD/NetBSD-${RELEASE}/images/"
    HASH=$(wget -q -O- "${URL}/MD5" | grep "${ISO}" | cut -d' ' -f4)
    echo "${URL}/${ISO} ${HASH}"
}

function get_nixos() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO="latest-nixos-${EDITION}-x86_64-linux.iso"
    local URL="https://channels.nixos.org/nixos-${RELEASE}"
    HASH=$(wget -q -O- "${URL}/${ISO}.sha256" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_openbsd() {
    local HASH=""
    local ISO="install${RELEASE//\./}.iso"
    local URL="https://mirror.leaseweb.com/pub/OpenBSD/${RELEASE}/amd64"
    HASH=$(wget -q -O- "${URL}/SHA256" | grep "${ISO}" | cut -d' ' -f4)
    echo "${URL}/${ISO} ${HASH}"
}

function get_openindiana(){
    local HASH=""
    local ISO=""
    local URL=""
    URL="https://dlc.openindiana.org/isos/hipster/${RELEASE}"
    ISO="OI-hipster-${EDITION}-${RELEASE}.iso"
    HASH=$(wget -q -O- "${URL}/${ISO}.sha256" |cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}
function get_opensuse() {
    local HASH=""
    local ISO=""
    local URL=""

    if [ "${RELEASE}" == "tumbleweed" ]; then
        ISO="openSUSE-Tumbleweed-DVD-x86_64-Current.iso"
        URL="https://download.opensuse.org/tumbleweed/iso"
    elif [ "${RELEASE}" == "microos" ]; then
        ISO="openSUSE-MicroOS-DVD-x86_64-Current.iso"
        URL="https://download.opensuse.org/tumbleweed/iso"
    elif [ "$RELEASE" == 15.0 ] || [ "$RELEASE" == 15.1 ]; then
        ISO="openSUSE-Leap-${RELEASE}-DVD-x86_64.iso"
        URL="https://download.opensuse.org/distribution/leap/${RELEASE}/iso"
    else
        ISO="openSUSE-Leap-${RELEASE}-DVD-x86_64-Current.iso"
        URL="https://download.opensuse.org/distribution/leap/${RELEASE}/iso"
    fi
    HASH=$(wget -q -O- "${URL}/${ISO}.sha256" |awk '{if(NR==4) print $0}'|cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_oraclelinux() {
    local HASH=""
    local ISO=""
    local VER_MAJ=${RELEASE::1}
    local VER_MIN=${RELEASE:2:1}
    local URL="https://yum.oracle.com/ISOS/OracleLinux/OL${VER_MAJ}/u${VER_MIN}/x86_64/"

    case ${VER_MAJ} in
      7) ISO="OracleLinux-R${VER_MAJ}-U${VER_MIN}-Server-x86_64-dvd.iso";;
      *) ISO="OracleLinux-R${VER_MAJ}-U${VER_MIN}-x86_64-dvd.iso";;
    esac
    HASH=$(wget -q -O- "https://linux.oracle.com/security/gpg/checksum/OracleLinux-R${VER_MAJ}-U${VER_MIN}-Server-x86_64.checksum" | grep "${ISO}" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_popos() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO=""
    local URL=""
    URL=$(wget -q -O- "https://api.pop-os.org/builds/${RELEASE}/${EDITION}" | jq -r .url)
    HASH=$(wget -q -O- "https://api.pop-os.org/builds/${RELEASE}/${EDITION}" | jq -r .sha_sum)
    echo "${URL} ${HASH}"
}

function get_reactos() {
    local HASH=""
    local URL=""
    local TMPURL=""

    TMPURL=$(wget -q -S -O- --max-redirect=0 "https://sourceforge.net/projects/reactos/files/latest/download" 2>&1 | grep -i Location | cut -d' ' -f4)
    URL=${TMPURL%\?*}
    echo "${URL} ${HASH}"
}

function get_rockylinux() {
    local EDITION="${1:-}"
    if [[ "${RELEASE}" =~ ^8. ]] && [[ "${EDITION}" == "dvd" ]]
    then
      EDITION="dvd1"
    fi
    local HASH=""
    local ISO="Rocky-${RELEASE}-x86_64-${EDITION}.iso"
    local URL=""

    case ${RELEASE} in
      9.1) URL="https://download.rockylinux.org/pub/rocky/9/isos/x86_64";;
      8.7) URL="https://download.rockylinux.org/pub/rocky/8/isos/x86_64";;
      *)   URL="http://dl.rockylinux.org/vault/rocky/${RELEASE}/isos/x86_64";;
    esac
    HASH=$(wget -q -O- "${URL}/CHECKSUM" | grep "SHA256" | grep "${ISO})" | cut -d' ' -f4)
    echo "${URL}/${ISO} ${HASH}"
}

function get_siduction() {
    local HASH=""
    local DATE=""
    local ISO=""
    local URL="https://mirrors.dotsrc.org/siduction/iso/Masters_of_War/${EDITION}"
    DATE=$(wget -q -O- "${URL}"| grep .iso.md5 | cut -d'-' -f6 | cut -d'.' -f1)
    HASH=$(wget -q -O- "${URL}/${ISO}.md5" | cut -d' ' -f1)
    ISO="siduction-22.1.1-Masters_of_War-${EDITION}-amd64-${DATE}.iso"
    echo "${URL}/${ISO} ${HASH}"
}

function get_slackware() {
    local HASH=""
    local ISO="slackware64-${RELEASE}-install-dvd.iso"
    local URL="https://slackware.nl/slackware/slackware-iso/slackware64-${RELEASE}-iso"
    HASH=$(wget -q -O- "${URL}/${ISO}.md5" |  cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_solus() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO="Solus-${RELEASE}-${EDITION}.iso"
    local URL="https://mirrors.rit.edu/solus/images/${RELEASE}"

    HASH=$(wget -q -O- "${URL}/${ISO}.sha256sum" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_holoiso() {
    local HASH=""
    local DATE="20221211"
    local ISO="HoloISO_${RELEASE}_OfflineInstaller-${DATE}_1636-x86_64.iso"
    local URL="http://holoiso.itsvixano.me"

    HASH=$(wget -q -O- "${URL}/${ISO}.sha256sum" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_tails() {
    local ISO=""
    local JSON=""
    local HASH=""
    local URL=""

    JSON="$(wget -q -O- "https://tails.boum.org/install/v2/Tails/amd64/${RELEASE}/latest.json")"
    URL=$(echo "${JSON}" | jq -r '.installations[0]."installation-paths"[]|select(.type=="iso")|."target-files"[0].url')
    HASH=$(echo "${JSON}" | jq -r '.installations[0]."installation-paths"[]|select(.type=="iso")|."target-files"[0].sha256')
    echo "${URL} ${HASH}"
}

function get_truenas-scale() {
    local ISO=""
    local URL=""

    local DLINFO="https://www.truenas.com/download-truenas-scale/"

    URL=$(wget -q ${DLINFO} -O- | grep -o "\"https://.*${RELEASE}.*\.iso\""|cut -d\" -f2)
    HASH=$(wget -q ${URL}.sha256 -O- | cut -d' ' -f1 )

    echo "${URL} ${HASH}"
}

function get_truenas-core() {
    local ISO=""
    local URL=""

    local DLINFO="https://www.truenas.com/download-truenas-core/"
    URL=$(wget -q ${DLINFO} -O- | grep -o "\"https://.*${RELEASE}.*\.iso\""|cut -d\" -f2)
    HASH=$(wget -q ${URL}.sha256 -O- | cut -d' ' -f1)

    echo "${URL} ${HASH}"
}

function get_ubuntu-server() {

      local HASH=""
      local ISO=""
      local URL="https://releases.ubuntu.com/${RELEASE}"

      if wget -q --spider "${URL}/SHA256SUMS"; then
          ISO=$(wget -q -O- "${URL}/SHA256SUMS" | grep 'live-server' | grep amd64 | grep iso | cut -d'*' -f2)
          HASH=$(wget -q -O- "${URL}/SHA256SUMS" | grep 'live-server' | grep amd64 | grep iso |cut -d' ' -f1)
      else
          ISO=$(wget -q -O- "${URL}/MD5SUMS" | grep 'live-server' | grep amd64 | grep iso | cut -d' ' -f3)
          HASH=$(wget -q -O- "${URL}/MD5SUMS" | grep 'live-server' | grep amd64 | grep iso | cut -d' ' -f1)
      fi

      if [[ "${RELEASE}" == *"daily"* ]] || [ "${RELEASE}" == "dvd" ]; then
          URL="https://cdimage.ubuntu.com/${OS}/${RELEASE}/current"
          ISO=$(wget -q -O- "${URL}/SHA256SUMS" | grep 'live-server' | grep amd64 | grep iso | cut -d'*' -f2)
          HASH=$(wget -q -O- "${URL}/SHA256SUMS" | grep 'live-server' | grep amd64 | grep iso |cut -d' ' -f1)
          zsync_get "${URL}/${ISO}" "${VM_PATH}" "${OS}-devel.iso"
          make_vm_config "${OS}-devel.iso"
      else
          web_get "${URL}/${ISO}" "${VM_PATH}"
          check_hash "${ISO}" "${HASH}"
          make_vm_config "${ISO}"
      fi
}

function get_ubuntu() {
    local ISO=""
    local HASH=""
    local URL=""

    if [[ "${RELEASE}" == *"daily"* ]] && [ "${OS}" == "ubuntustudio" ]; then
        # Ubuntu Studio daily-live images are in the dvd directory
        RELEASE="dvd"
    elif [ "${RELEASE}" == "daily-canary" ] && [ "${OS}" != "ubuntu" ]; then
        # daily-canary is only available for Ubuntu, switch flavours to daily-live
        RELEASE="daily-live"
    elif [ "${RELEASE}" == "daily-legacy" ] && [ "${OS}" != "ubuntu" ]; then
        # daily-legacy is only available for Ubuntu, switch flavours to daily-live
        RELEASE="daily-live"
    fi

    if [[ "${RELEASE}" == "eol-"* ]]; then
        URL="https://old-releases.ubuntu.com/releases/${RELEASE/eol-/}"
    elif [[ "${RELEASE}" == "jammy-daily" ]]; then
        URL="https://cdimage.ubuntu.com/${OS}/jammy/daily-live/current"
        VM_PATH="${OS}-jammy-live"
    elif [[ "${RELEASE}" == "daily-legacy" ]]; then
        URL="https://cdimage.ubuntu.com/${RELEASE}/current"
        VM_PATH="${OS}-${RELEASE}"
    elif [[ "${RELEASE}" == *"daily"* ]] || [ "${RELEASE}" == "dvd" ]; then
        URL="https://cdimage.ubuntu.com/${OS}/${RELEASE}/current"
        VM_PATH="${OS}-${RELEASE}"
    elif [ "${OS}" == "ubuntu" ]; then
        URL="https://releases.ubuntu.com/${RELEASE}"
    else
        URL="https://cdimage.ubuntu.com/${OS}/releases/${RELEASE}/release"
    fi

    if wget -q --spider "${URL}/SHA256SUMS"; then
        ISO=$(wget -q -O- "${URL}/SHA256SUMS" | grep 'desktop\|dvd\|install' | grep amd64 | grep iso | cut -d'*' -f2)
        HASH=$(wget -q -O- "${URL}/SHA256SUMS" | grep 'desktop\|dvd\|install' | grep amd64 | grep iso |cut -d' ' -f1)
    else
        ISO=$(wget -q -O- "${URL}/MD5SUMS" | grep 'desktop\|dvd\|install' | grep amd64 | grep iso | cut -d' ' -f3)
        HASH=$(wget -q -O- "${URL}/MD5SUMS" | grep 'desktop\|dvd\|install' | grep amd64 | grep iso | cut -d' ' -f1)
    fi

    if [[ "${RELEASE}" == *"daily"* ]] || [ "${RELEASE}" == "dvd" ]; then
        zsync_get "${URL}/${ISO}" "${VM_PATH}" "${OS}-devel.iso"
        make_vm_config "${OS}-devel.iso"
    else
        web_get "${URL}/${ISO}" "${VM_PATH}"
        check_hash "${ISO}" "${HASH}"
        make_vm_config "${ISO}"
    fi
}

function get_void() {
    local DATE=""
    local EDITION="${1:-}"
    local HASH=""
    local ISO=""
    local URL="https://alpha.de.repo.voidlinux.org/live/current"

    DATE=$(wget -q -O- "${URL}/sha256sum.txt" | head -n1 | cut -d'.' -f1 | cut -d'-' -f4)
    case ${EDITION} in
        glibc)      ISO="void-live-x86_64-${DATE}-base.iso";;
        musl)       ISO="void-live-x86_64-musl-${DATE}-base.iso";;
        xfce-glibc) ISO="void-live-x86_64-${DATE}-xfce.iso";;
        xfce-musl)  ISO="void-live-x86_64-musl-${DATE}-xfce.iso";;
    esac
    HASH="$(wget -q -O- "${URL}/sha256sum.txt" | grep "${ISO}" | cut -d' ' -f4)"
    echo "${URL}/${ISO} ${HASH}"
}


function get_xerolinux() {
    local HASH=""
    local URL=""
    local ISO="xerolinux-2022.12-x86_64.iso"
    local URL="https://sourceforge.net/projects/xerolinux/files/Releases"

    HASH=$(wget -q -O- "${URL}/${ISO}.sha256" | cut -d' ' -f1)
    echo "${URL}/${ISO} ${HASH}"
}

function get_zorin() {
    local EDITION="${1:-}"
    local HASH=""
    local ISO=""
    local URL=""

    # Parse out the iso URL from the redirector
    URL=$(wget -q -S -O- --max-redirect=0 "https://zrn.co/${RELEASE}${EDITION}" 2>&1 | grep Location | cut -d' ' -f4)
    echo "${URL} ${HASH}"
}

function get_vxlinux() {
    local HASH=""
    local ISO=""
    local URL="https://github.com/dessington/vx-linux/releases/download/${RELEASE}"

    if [ "$RELEASE" == "4.0" ]; then
        ISO="vx-linux-4.0-qt.iso"
    else
        ISO="vx-linux-${RELEASE}.iso"
    fi
    echo "${URL}/${ISO} ${HASH}"
}

function unattended_windows() {
    cat << 'EOF' > "${1}"
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend"
  xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <!--
       For documentation on components:
       https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/
  -->
  <settings pass="offlineServicing">
    <component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <EnableLUA>false</EnableLUA>
    </component>
    <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <ComputerName>*</ComputerName>
    </component>
  </settings>

  <settings pass="generalize">
    <component name="Microsoft-Windows-PnPSysprep" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
      <PersistAllDeviceInstalls>true</PersistAllDeviceInstalls>
    </component>
    <component name="Microsoft-Windows-Security-SPP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <SkipRearm>1</SkipRearm>
    </component>
  </settings>

  <settings pass="specialize">
    <component name="Microsoft-Windows-Security-SPP-UX" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <SkipAutoActivation>true</SkipAutoActivation>
    </component>
    <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <ComputerName>*</ComputerName>
      <OEMInformation>
        <Manufacturer>Quickemu Project</Manufacturer>
        <Model>Quickemu</Model>
        <SupportHours>24/7</SupportHours>
        <SupportPhone></SupportPhone>
        <SupportProvider>Quickemu Project</SupportProvider>
        <SupportURL>https://github.com/quickemu-project/quickemu/issues</SupportURL>
      </OEMInformation>
      <OEMName>Quickemu Project</OEMName>
      <ProductKey>W269N-WFGWX-YVC9B-4J6C9-T83GX</ProductKey>
    </component>
    <component name="Microsoft-Windows-SQMApi" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <CEIPEnabled>0</CEIPEnabled>
    </component>
  </settings>

  <settings pass="windowsPE">
    <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Diagnostics>
        <OptIn>false</OptIn>
      </Diagnostics>
      <DiskConfiguration>
        <Disk wcm:action="add">
          <DiskID>0</DiskID>
          <WillWipeDisk>true</WillWipeDisk>
          <CreatePartitions>
            <!-- Windows RE Tools partition -->
            <CreatePartition wcm:action="add">
              <Order>1</Order>
              <Type>Primary</Type>
              <Size>256</Size>
            </CreatePartition>
            <!-- System partition (ESP) -->
            <CreatePartition wcm:action="add">
              <Order>2</Order>
              <Type>EFI</Type>
              <Size>128</Size>
            </CreatePartition>
            <!-- Microsoft reserved partition (MSR) -->
            <CreatePartition wcm:action="add">
              <Order>3</Order>
              <Type>MSR</Type>
              <Size>128</Size>
            </CreatePartition>
            <!-- Windows partition -->
            <CreatePartition wcm:action="add">
              <Order>4</Order>
              <Type>Primary</Type>
              <Extend>true</Extend>
            </CreatePartition>
          </CreatePartitions>
          <ModifyPartitions>
            <!-- Windows RE Tools partition -->
            <ModifyPartition wcm:action="add">
              <Order>1</Order>
              <PartitionID>1</PartitionID>
              <Label>WINRE</Label>
              <Format>NTFS</Format>
              <TypeID>DE94BBA4-06D1-4D40-A16A-BFD50179D6AC</TypeID>
            </ModifyPartition>
            <!-- System partition (ESP) -->
            <ModifyPartition wcm:action="add">
              <Order>2</Order>
              <PartitionID>2</PartitionID>
              <Label>System</Label>
              <Format>FAT32</Format>
            </ModifyPartition>
            <!-- MSR partition does not need to be modified -->
            <ModifyPartition wcm:action="add">
              <Order>3</Order>
              <PartitionID>3</PartitionID>
            </ModifyPartition>
            <!-- Windows partition -->
              <ModifyPartition wcm:action="add">
              <Order>4</Order>
              <PartitionID>4</PartitionID>
              <Label>Windows</Label>
              <Letter>C</Letter>
              <Format>NTFS</Format>
            </ModifyPartition>
          </ModifyPartitions>
        </Disk>
      </DiskConfiguration>
      <DynamicUpdate>
        <Enable>true</Enable>
        <WillShowUI>Never</WillShowUI>
      </DynamicUpdate>
      <ImageInstall>
        <OSImage>
          <InstallTo>
            <DiskID>0</DiskID>
            <PartitionID>4</PartitionID>
          </InstallTo>
          <InstallToAvailablePartition>false</InstallToAvailablePartition>
        </OSImage>
      </ImageInstall>
      <RunSynchronous>
        <RunSynchronousCommand wcm:action="add">
          <Order>1</Order>
          <Path>reg add HKLM\System\Setup\LabConfig /v BypassCPUCheck /t REG_DWORD /d 0x00000001 /f</Path>
        </RunSynchronousCommand>
        <RunSynchronousCommand wcm:action="add">
          <Order>2</Order>
          <Path>reg add HKLM\System\Setup\LabConfig /v BypassRAMCheck /t REG_DWORD /d 0x00000001 /f</Path>
        </RunSynchronousCommand>
        <RunSynchronousCommand wcm:action="add">
          <Order>3</Order>
          <Path>reg add HKLM\System\Setup\LabConfig /v BypassSecureBootCheck /t REG_DWORD /d 0x00000001 /f</Path>
        </RunSynchronousCommand>
        <RunSynchronousCommand wcm:action="add">
          <Order>4</Order>
          <Path>reg add HKLM\System\Setup\LabConfig /v BypassTPMCheck /t REG_DWORD /d 0x00000001 /f</Path>
        </RunSynchronousCommand>
      </RunSynchronous>
      <UpgradeData>
        <Upgrade>false</Upgrade>
        <WillShowUI>Never</WillShowUI>
      </UpgradeData>
      <UserData>
        <AcceptEula>true</AcceptEula>
        <FullName>Quickemu</FullName>
        <Organization>Quickemu Project</Organization>
        <!-- https://docs.microsoft.com/en-us/windows-server/get-started/kms-client-activation-keys -->
        <ProductKey>
          <Key>W269N-WFGWX-YVC9B-4J6C9-T83GX</Key>
          <WillShowUI>Never</WillShowUI>
        </ProductKey>
      </UserData>
    </component>

    <component name="Microsoft-Windows-PnpCustomizationsWinPE" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" processorArchitecture="amd64" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <!--
           This makes the VirtIO drivers available to Windows, assuming that
           the VirtIO driver disk is available as drive E:
           https://github.com/virtio-win/virtio-win-pkg-scripts/blob/master/README.md
      -->
      <DriverPaths>
        <PathAndCredentials wcm:action="add" wcm:keyValue="1">
          <Path>E:\qemufwcfg\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="2">
          <Path>E:\vioinput\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="3">
          <Path>E:\vioscsi\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="4">
          <Path>E:\viostor\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="5">
          <Path>E:\vioserial\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="6">
          <Path>E:\qxldod\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="7">
          <Path>E:\amd64\w10</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="8">
          <Path>E:\viogpudo\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="9">
          <Path>E:\viorng\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="10">
          <Path>E:\NetKVM\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="11">
          <Path>E:\viofs\w10\amd64</Path>
        </PathAndCredentials>
        <PathAndCredentials wcm:action="add" wcm:keyValue="12">
          <Path>E:\Balloon\w10\amd64</Path>
        </PathAndCredentials>
      </DriverPaths>
    </component>
  </settings>

  <settings pass="oobeSystem">
    <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <AutoLogon>
        <Password>
          <Value>quickemu</Value>
          <PlainText>true</PlainText>
        </Password>
        <Enabled>true</Enabled>
        <Username>Quickemu</Username>
      </AutoLogon>
      <DisableAutoDaylightTimeSet>false</DisableAutoDaylightTimeSet>
      <OOBE>
        <HideEULAPage>true</HideEULAPage>
        <HideLocalAccountScreen>true</HideLocalAccountScreen>
        <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
        <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
        <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
        <NetworkLocation>Home</NetworkLocation>
        <ProtectYourPC>3</ProtectYourPC>
        <SkipUserOOBE>true</SkipUserOOBE>
        <SkipMachineOOBE>true</SkipMachineOOBE>
        <VMModeOptimizations>
          <SkipWinREInitialization>true</SkipWinREInitialization>
        </VMModeOptimizations>
      </OOBE>
      <UserAccounts>
        <LocalAccounts>
          <LocalAccount wcm:action="add">
            <Password>
              <Value>quickemu</Value>
              <PlainText>true</PlainText>
            </Password>
            <Description>Quickemu</Description>
            <DisplayName>Quickemu</DisplayName>
            <Group>Administrators</Group>
            <Name>Quickemu</Name>
          </LocalAccount>
        </LocalAccounts>
      </UserAccounts>
      <RegisteredOrganization>Quickemu Project</RegisteredOrganization>
      <RegisteredOwner>Quickemu</RegisteredOwner>
      <FirstLogonCommands>
        <SynchronousCommand wcm:action="add">
          <CommandLine>msiexec /i E:\guest-agent\qemu-ga-x86_64.msi /quiet /passive /qn</CommandLine>
          <Description>Install Virtio Guest Agent</Description>
          <Order>1</Order>
        </SynchronousCommand>
        <SynchronousCommand wcm:action="add">
          <CommandLine>msiexec /i F:\spice-webdavd-x64-latest.msi /quiet /passive /qn</CommandLine>
          <Description>Install spice-webdavd file sharing agent</Description>
          <Order>2</Order>
        </SynchronousCommand>
        <SynchronousCommand wcm:action="add">
          <CommandLine>msiexec /i F:\UsbDk_1.0.22_x64.msi /quiet /passive /qn</CommandLine>
          <Description>Install usbdk USB sharing agent</Description>
          <Order>3</Order>
        </SynchronousCommand>
        <SynchronousCommand wcm:action="add">
          <CommandLine>msiexec /i F:\spice-vdagent-x64-0.10.0.msi /quiet /passive /qn</CommandLine>
          <Description>Install spice-vdagent SPICE agent</Description>
          <Order>4</Order>
        </SynchronousCommand>
        <SynchronousCommand wcm:action="add">
          <CommandLine>Cmd /c POWERCFG -H OFF</CommandLine>
          <Description>Disable Hibernation</Description>
          <Order>5</Order>
        </SynchronousCommand>
      </FirstLogonCommands>
    </component>
  </settings>
</unattend>
EOF
}


function get_windows() {
    # Use the iTechtics CDN to download the ISOs.
    # - https://www.itechtics.com/windows-10-download-iso/
    # - https://www.itechtics.com/windows-11-download-iso/
    #  0 : Prompt for a manual ISO download
    #  1 : Download automatically
    local AUTO_DOWNLOAD=1
    local DOWNLOAD_URL=""

    if [ ${AUTO_DOWNLOAD} -eq 1 ]; then
        # Ignore the most recent Windows 10 release for now.
        case ${RELEASE} in
            10) DOWNLOAD_URL="https://www.itechtics.com/?dl_id=173"
                EDITION="22H2"
                FILE_NAME="Win${RELEASE}_${EDITION}_EnglishInternational_x64v1.iso"
                FILE_HASH="dc3982ad27e2d4e03b680630c28f824cb78bcd47"
                ;;
            11) DOWNLOAD_URL="https://www.itechtics.com/?dl_id=168"
                EDITION="22H2"
                FILE_NAME="Win${RELEASE}_${EDITION}_English_x64v1.iso"
                FILE_HASH="c5341ba26e420684468fa4d4ab434823c9d1b61f"
                ;;
        esac

        echo "Downloading Windows ${RELEASE} ${EDITION}..."
        web_get "${DOWNLOAD_URL}" "${VM_PATH}" "${FILE_NAME}"

        check_hash "${FILE_NAME}" "${FILE_HASH}"
    else
        case ${RELEASE} in
            10) WINDOWS_ISO_URL="https://www.microsoft.com/software-download/windows10";;
            11) WINDOWS_ISO_URL="https://www.microsoft.com/software-download/windows11";;
        esac
        echo "######################################################################"
        echo "# Download a Windows ${RELEASE} .iso image from:"
        echo "#  - ${WINDOWS_ISO_URL}"
        echo "# Put the .iso image in the ${VM_PATH} directory and rename"
        echo "# it to windows-${RELEASE}.iso."
        echo "######################################################################"
    fi

    web_get "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso" "${VM_PATH}"

    rm -f "${VM_PATH}/unattended.iso"
    case ${RELEASE} in
        10|11)
            echo "Making unattended.iso"
            mkdir -p "${VM_PATH}/unattended" 2>/dev/null
            web_get https://www.spice-space.org/download/windows/spice-webdavd/spice-webdavd-x64-latest.msi "${VM_PATH}/unattended"
            web_get https://www.spice-space.org/download/windows/vdagent/vdagent-win-0.10.0/spice-vdagent-x64-0.10.0.msi "${VM_PATH}/unattended"
            web_get https://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.22_x64.msi "${VM_PATH}/unattended"
            unattended_windows "${VM_PATH}/unattended/autounattend.xml"
            mkisofs -quiet -l -o "${VM_PATH}/unattended.iso" "${VM_PATH}/unattended/"
            ;;
    esac

    case "${AUTO_DOWNLOAD}" in
        0) make_vm_config "windows-${RELEASE}.iso" "virtio-win.iso";;
        1) make_vm_config "${FILE_NAME}" "virtio-win.iso";;
    esac
}

create_vm() {
    # shellcheck disable=SC2206
    local URL_HASH=(${1// / })
    local URL="${URL_HASH[0]}"
    local HASH="${URL_HASH[1]}"
    local ISO="${URL##*/}"

    #echo "${URL}"
    #echo "${ISO}"
    #echo "${HASH}"
    web_get "${URL}" "${VM_PATH}"

    if [ -n "${HASH}" ]; then
      check_hash "${ISO}" "${HASH}"
    fi

    if [ ${OS} == "freedos" ] && [[ $ISO =~ ".zip" ]]; then
        unzip ${VM_PATH}/${ISO} -d ${VM_PATH}
        ISO=$(ls ${VM_PATH} | grep -i '.iso')
    fi
    if [[ ${OS} == "batocera" ]] && [[ ${ISO} =~ ".gz" ]]; then
        gzip -d "${VM_PATH}/${ISO}"
        ISO="${ISO/.gz/}"
    fi

    #  Could be other OS iso files compressed with bzip2 or gzip
    #  but for now we'll keep this to know cases
    if [[ ${OS} == "dragonflybsd" ]] && [[ ${ISO} =~ ".bz2" ]]; then
        bzip2 -d  "${VM_PATH}/${ISO}"
        ISO="${ISO/.bz2/}"
    fi

    if [ ${OS} == "reactos" ] && [[ $ISO =~ ".zip" ]]; then
        unzip ${VM_PATH}/${ISO} -d ${VM_PATH}
        ISO=$(ls ${VM_PATH} | grep -i '.iso' | grep -v '.zip')
    fi

    make_vm_config "${ISO}"
}

trap cleanup EXIT

if ((BASH_VERSINFO[0] < 4)); then
    echo "Sorry, you need bash 4.0 or newer to run this script."
    exit 1
fi

LANGS=()

if [ -n "${1}" ]; then
    OS="${1,,}"
    if [ "${OS}" == "list" ] || [ "${OS}" == "list_csv" ]; then
        list_csv
    elif [ "${OS}" == "list_json" ]; then
        list_json
    elif [ "${OS}" == "--version" ] || [ "${OS}" == "-version" ] || [ "${OS}" == "version" ]; then
        WHERE=$(dirname "${BASH_SOURCE[0]}")
        "${WHERE}/quickemu" --version
        exit 0
    fi
else
    echo "ERROR! You must specify an operating system."
    echo -n " - Operating Systems: "
    os_support
    exit 1
fi

if [[ ! $(os_support) =~ ${OS} ]]; then
    echo -e "ERROR! ${OS} is not a supported OS.\n"
    os_support
    exit 1
fi

if [ -n "${2}" ]; then
    RELEASE="${2,,}"
    VM_PATH="${OS}-${RELEASE}"

    # If the OS has an editions_() function, use it.
    if [[ $(type -t "editions_${OS}") == function ]]; then
        EDITIONS=($(editions_${OS}))
        EDITION=${EDITIONS[0]}
        if [ -n "${3}" ]; then
            EDITION="${3}"
            if [[ ! ${EDITIONS[*]} =~ ${EDITION} ]]; then
                echo -e "ERROR! ${EDITION} is not a supported $(pretty_name "${OS}") edition:\n"
                for EDITION in "${EDITIONS[@]}"; do
                  echo -n "${EDITION} "
                done
                exit 1
            fi
        fi

        # Handle odd missing fedora cominations
        if [[ $OS == fedora ]] ; then
            if [[ ${RELEASE} = "33"  &&  ${EDITION} = "i3"  ]] || [[  ${RELEASE} = "34"  &&  ${EDITION} = "Cinnamon"   ]] ; then
                echo "ERROR! Unsupported combination"
                echo "       Fedora 33 i3 and Fedora 34 Cinnamon are not available, please choose another Release or Edition"
                exit 1;
            fi
        fi


        VM_PATH="${OS}-${RELEASE}-${EDITION}"
        validate_release "releases_${OS}"
        create_vm "$("get_${OS}" "${EDITION}")"
    elif [ "${OS}" == "macos" ]; then
        # macOS doesn't use create_vm()
        validate_release releases_macos
        get_macos
    elif [[ "${OS}" == *"ubuntu-server"* ]]; then
        # (Comes before regular Ubuntu, or the code tries to download the desktop) #
        # Ubuntu doesn't use create_vm()
        validate_release releases_ubuntu-server
        get_ubuntu-server
    elif [[ "${OS}" == *"ubuntu"* ]]; then
        # Ubuntu doesn't use create_vm()
        validate_release releases_ubuntu
        get_ubuntu
    elif [[ "${OS}" == *"deepin"* ]]; then
        # deepin doesn't use create_vm()
        validate_release releases_deepin
        get_deepin
    elif [ "${OS}" == "windows" ]; then
        # Windows doesn't use create_vm()
        validate_release releases_windows
        get_windows
    else
        validate_release "releases_${OS}"
        create_vm "$("get_${OS}")"
    fi
else
    echo "ERROR! You must specify a release."
    case ${OS} in
      *ubuntu-server*)
        echo -n " - Releases: "
        releases_ubuntu-server | sed -Ee 's/eol-\S+//g' # hide eol releases
        ;;
      *ubuntu*)
        echo -n " - Releases: "
        releases_ubuntu | sed -Ee 's/eol-\S+//g' # hide eol releases
        ;;

      *)
        echo -n " - Releases: "
        releases_"${OS}"
        if [[ $(type -t "editions_${OS}") == function ]]; then
          echo -n " - Editions: "
          editions_"${OS}"
        fi
        ;;
    esac
    exit 1
fi

# vim:tabstop=4:shiftwidth=4:expandtab