From 30400d79669624f97ebe542706e35efd2d0ed012 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 27 Feb 2023 22:35:32 +1100 Subject: [PATCH 01/24] Update syno_hdd_db.sh For WD drives add extra model without "WDC " to fix issue #1 --- syno_hdd_db.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index f374ae1..7a1d611 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -66,6 +66,20 @@ for drive in /dev/sata*; do if [[ $hdmodel ]] && [[ $fwrev ]]; then hdparm+=("${hdmodel},${fwrev}") fi + + # Add extra model without "WDC " to fix issue #1 + if [[ $hdmodel =~ ^WDC.* ]]; then + hdmodel2=${hdmodel#"WDC "} # Remove "WDC " from start + #echo "$hdmodel2" " Without 'WDC ' brand" # debug + shopt -s extglob + hdmodel2=${hdmodel2/#*([[:space:]])} # Remove leading spaces + #echo "$hdmodel2" " Without leading spaces" # debug + shopt -u extglob + if [[ $hdmodel2 ]] && [[ $fwrev ]]; then + hdparm+=("${hdmodel2},${fwrev}") + fi + fi + fi done @@ -78,6 +92,20 @@ for drive in /dev/sd*; do if [[ $hdmodel ]] && [[ $fwrev ]]; then hdparm+=("${hdmodel},${fwrev}") fi + + # Add extra model without "WDC " to fix issue #1 + if [[ $hdmodel =~ ^WDC.* ]]; then + hdmodel2=${hdmodel#"WDC "} # Remove "WDC " from start + #echo "$hdmodel2" " Without 'WDC ' brand" # debug + shopt -s extglob + hdmodel2=${hdmodel2/#*([[:space:]])} # Remove leading spaces + #echo "$hdmodel2" " Without leading spaces" # debug + shopt -u extglob + if [[ $hdmodel2 ]] && [[ $fwrev ]]; then + hdparm+=("${hdmodel2},${fwrev}") + fi + fi + fi done From 0729382798e0e08ef4a3d839807e55aad65e7e25 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Thu, 9 Mar 2023 19:37:32 +1100 Subject: [PATCH 02/24] Update syno_hdd_db.sh Bug fix for SAS drives that work with hdparm. --- syno_hdd_db.sh | 324 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 234 insertions(+), 90 deletions(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index 7a1d611..9a1b6c3 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -18,27 +18,83 @@ # sudo /volume1/scripts/syno_hdd_db.sh # or # sudo /volume1/scripts/syno_hdd_db.sh -showedits +# or +# sudo /volume1/scripts/syno_hdd_db.sh -force -showedits #-------------------------------------------------------------------------------------------------- # TODO # Detect if expansion unit(s) connected and get model(s) and edit expansion unit db files. # Or add support for specifying user's expansion unit model(s) as arguments. # Or maybe use the shotgun approach and update all expansion unit db files. -# Add support for SAS drives? Are are listed as /dev/sata# or /dev/sas# ? +# +# Add support for M.2 SATA and NVMe drives on a M2D17 PCI card. +# +# Maybe also edit the other disk compatibility DB in synoboot, used during boot time. +# It's also parsed and checked and probably in some cases it could be more critical to patch that one instead. # DONE +# Add support for SAS drives. +# +# Get HDD/SSD/SAS drive model number with smartctl instead of hdparm. +# +# Check if there is a newer script version available. +# # Add support for NVMe drives. +# +# Prevent DSM auto updating the drive database. +# +# Optionally disable "support_disk_compatibility". -# Check for -s or -showedits flag -if [[ ${1,,} == "-s" ]] || [[ ${1,,} == "-showedits" ]]; then showedits=yes; fi +scriptver="1.1.9" + +# Check latest release with GitHub API +get_latest_release() { + curl --silent "https://api.github.com/repos/$1/releases/latest" | + grep '"tag_name":' | # Get tag line + sed -E 's/.*"([^"]+)".*/\1/' # Pluck JSON value +} + +tag=$(get_latest_release "007revad/Synology_HDD_db") + +if [[ ${tag:1} > "$scriptver" ]]; then + echo "There is a newer version of this script available." + echo -e "Current version: ${scriptver}\nLatest version: ${tag:1}" + echo "https://github.com/007revad/Synology_HDD_db/releases/latest" + echo "" + sleep 10 +fi + + +# Check for flags with getopts +OPTERR=0 +while getopts "sfn" option; do + # Need to ensure any other long flags do not contain s, n, or f + if [[ ! ${#option} -gt "1" ]]; then + case ${option,,,} in + s) + showedits=yes + #echo showedits # debug + ;; + n) + nodbupdate=yes # For future use + ;; + f) + force=yes + ;; + *) + ;; + esac + fi +done + model=$(cat /proc/sys/kernel/syno_hw_version) model=${model,,} # convert to lower case # Check for -j after model - GitHub issue #2 if [[ $model =~ '-j'$ ]]; then - model=${model%??} # remove last to chars + model=${model%??} # remove last two chars fi # Get DSM major version @@ -55,60 +111,109 @@ fi #------------------------------------------------------------------------------ -# Get list of installed HDDs and SATA SSDs - -# SATA drives, sata1, sata2 etc -for drive in /dev/sata*; do - if [[ $drive =~ /dev/sata[1-9][0-9]?[0-9]?$ ]]; then - tmp=$(hdparm -i "$drive" | grep Model) - hdmodel=$(printf %s "$tmp" | cut -d"," -f 1 | cut -d"=" -f 2) - fwrev=$(printf %s "$tmp" | cut -d"," -f 2 | cut -d"=" -f 2) - if [[ $hdmodel ]] && [[ $fwrev ]]; then - hdparm+=("${hdmodel},${fwrev}") - fi - - # Add extra model without "WDC " to fix issue #1 - if [[ $hdmodel =~ ^WDC.* ]]; then - hdmodel2=${hdmodel#"WDC "} # Remove "WDC " from start - #echo "$hdmodel2" " Without 'WDC ' brand" # debug - shopt -s extglob - hdmodel2=${hdmodel2/#*([[:space:]])} # Remove leading spaces - #echo "$hdmodel2" " Without leading spaces" # debug - shopt -u extglob - if [[ $hdmodel2 ]] && [[ $fwrev ]]; then - hdparm+=("${hdmodel2},${fwrev}") - fi - fi +# Get list of installed SATA, SAS and NVMe drives +getModel() { + hdmodel=$(smartctl -i "$1" | grep -i "Device Model:" | awk '{print $3 $4 $5}') + if [[ ! $hdmodel ]]; then + hdmodel=$(smartctl -i "$1" | grep -i "Product:" | awk '{print $2 $3 $4}') fi -done + #echo "Model: $hdmodel" # debug + + # Brands that return "BRAND " and need "BRAND " removed. + hdmodel=${hdmodel#"WDC "} # Remove "WDC " from start of model name + hdmodel=${hdmodel#"HGST "} # Remove "HGST " from start of model name + hdmodel=${hdmodel#"TOSHIBA "} # Remove "TOSHIBA " from start of model name + + # Old drive brands + hdmodel=${hdmodel#"Hitachi "} # Remove "Hitachi " from start of model name + hdmodel=${hdmodel#"SAMSUNG "} # Remove "SAMSUNG " from start of model name + hdmodel=${hdmodel#"FUJISTU "} # Remove "FUJISTU " from start of model name + hdmodel=${hdmodel#"APPLE HDD "} # Remove "APPLE HDD " from start of model name + + shopt -s extglob + hdmodel=${hdmodel/#*([[:space:]])} # Remove leading spaces + hdmodel=${hdmodel/%*([[:space:]])} # Remove trailing spaces + shopt -u extglob + #echo "Model: $hdmodel" # debug +} -# SATA drives sda, sdb etc -for drive in /dev/sd*; do - if [[ $drive =~ /dev/sd[a-z]{1,3}$ ]]; then - tmp=$(hdparm -i "$drive" | grep Model) - hdmodel=$(printf %s "$tmp" | cut -d"," -f 1 | cut -d"=" -f 2) - fwrev=$(printf %s "$tmp" | cut -d"," -f 2 | cut -d"=" -f 2) - if [[ $hdmodel ]] && [[ $fwrev ]]; then - hdparm+=("${hdmodel},${fwrev}") - fi - - # Add extra model without "WDC " to fix issue #1 - if [[ $hdmodel =~ ^WDC.* ]]; then - hdmodel2=${hdmodel#"WDC "} # Remove "WDC " from start - #echo "$hdmodel2" " Without 'WDC ' brand" # debug - shopt -s extglob - hdmodel2=${hdmodel2/#*([[:space:]])} # Remove leading spaces - #echo "$hdmodel2" " Without leading spaces" # debug - shopt -u extglob - if [[ $hdmodel2 ]] && [[ $fwrev ]]; then - hdparm+=("${hdmodel2},${fwrev}") - fi +getFwVersion() { + if [[ $2 == "sas" ]]; then + # hdparm does not work with some SAS drives + fwrev=$(smartctl -i "$1" | grep -i "Firmware Version:" | awk '{print $3}') + if [[ ! $hdmodel ]]; then + fwrev=$(smartctl -i "$1" | grep -i "Revision:" | awk '{print $2}') fi + else + tmp=$(hdparm -i "$1" | grep Model) + fwrev=$(printf %s "$tmp" | cut -d"," -f 2 | cut -d"=" -f 2) + fi + #echo "Firmware: $fwrev" # debug +} + +getNVMeModel() { + nvmemodel=$(cat $1/model) + shopt -s extglob + nvmemodel=${nvmemodel/#*([[:space:]])} # Remove leading spaces + nvmemodel=${nvmemodel/%*([[:space:]])} # Remove trailing spaces + shopt -u extglob + #echo "NVMe Model: $nvmemodel" # debug +} + +getNVMeFwVersion() { + nvmefw=$(cat $1/firmware_rev) + nvmefw=$(echo "$nvmefw" | xargs) # trim leading and trailing white space + #echo "NVMe Firmware: $nvmefw" # debug +} + +for d in `cat /proc/partitions | awk '{print $4}'`; do + if [ ! -e /dev/$d ]; then + continue; fi + #echo $d # debug + case "$d" in + hd*|sd*) + if [[ $d =~ [hs]d[a-z]{1,2}$ ]]; then + #echo -e "\n$d" # debug + getModel "/dev/$d" + getFwVersion "/dev/$d" + if [[ $hdmodel ]] && [[ $fwrev ]]; then + hdparm+=("${hdmodel},${fwrev}") + fi + fi + ;; + sas*|sata*) + if [[ $d =~ (sas|sata)[0-9][0-9]?[0-9]?$ ]]; then + #echo -e "\n$d" # debug + getModel "/dev/$d" + if [[ $d =~ (sas)[0-9][0-9]?[0-9]?$ ]]; then + # hdparm does not work with some SAS drives + getFwVersion "/dev/$d" "sas" + else + getFwVersion "/dev/$d" + fi + if [[ $hdmodel ]] && [[ $fwrev ]]; then + hdparm+=("${hdmodel},${fwrev}") + fi + fi + ;; + nvme*) + if [[ $d =~ nvme[0-9][0-9]?n[0-9][0-9]?$ ]]; then + #echo -e "\n$d" # debug + n=n$(printf "$d" | cut -d "n" -f 2) + getNVMeModel "/sys/class/nvme/$n" + getNVMeFwVersion "/sys/class/nvme/$n" + if [[ $nvmemodel ]] && [[ $nvmefw ]]; then + nvmelist+=("${nvmemodel},${nvmefw}") + fi + fi + ;; + esac done + # Sort hdparm array into new hdds array to remove duplicates if [[ ${#hdparm[@]} -gt "0" ]]; then while IFS= read -r -d '' x; do @@ -130,44 +235,24 @@ else fi -#------------------------------------------------------------------------------ -# Get list of installed NVMe drives - -express=$(cat /proc/devices | grep nvme) -if [[ $express ]]; then - for path in /sys/class/nvme/*; do - nvmemodel=$(cat "$path"/model) - nvmemodel=$(echo "$nvmemodel" | xargs) # trim leading and trailing white space - #if [[ $nvmemodel ]]; then echo "NVMe model: ${nvmemodel}"; fi # debug - - nvmefw=$(cat "$path"/firmware_rev) - nvmefw=$(echo "$nvmefw" | xargs) # trim leading and trailing white space - #if [[ $nvmefw ]]; then echo "NVMe firmware: ${nvmefw}"; fi # debug +# Sort nvmelist array into new nvmes array to remove duplicates +if [[ ${#nvmelist[@]} -gt "0" ]]; then + while IFS= read -r -d '' x; do + nvmes+=("$x") + done < <(printf "%s\0" "${nvmelist[@]}" | sort -uz) +fi - if [[ $nvmemodel ]] && [[ $nvmefw ]]; then - nvmelist+=("${nvmemodel},${nvmefw}") - fi +# Check nvmes array isn't empty +if [[ ${#nvmes[@]} -eq "0" ]]; then + echo -e "No NVMe drives found\n" +else + echo "NVMe drive models found: ${#nvmes[@]}" + num="0" + while [[ $num -lt "${#nvmes[@]}" ]]; do + echo "${nvmes[num]}" + num=$((num +1)) done - - # Sort nvmelist array into new nvmes array to remove duplicates - if [[ ${#nvmelist[@]} -gt "0" ]]; then - while IFS= read -r -d '' x; do - nvmes+=("$x") - done < <(printf "%s\0" "${nvmelist[@]}" | sort -uz) - fi - - # Check hdds array isn't empty - if [[ ${#nvmes[@]} -eq "0" ]]; then - echo -e "No NVMe drives found\n" - else - echo "NVMe drive models found: ${#nvmes[@]}" - num="0" - while [[ $num -lt "${#nvmes[@]}" ]]; do - echo "${nvmes[num]}" - num=$((num +1)) - done - echo - fi + echo fi @@ -251,23 +336,82 @@ while [[ $num -lt "${#nvmes[@]}" ]]; do done +# Optionally disable "support_disk_compatibility" +sdc=support_disk_compatibility +setting="$(get_key_value /etc.defaults/synoinfo.conf $sdc)" +if [[ $force == "yes" ]]; then + if [[ $setting == "yes" ]]; then + # Disable support_disk_compatibility + sed -i "s/${sdc}=\"yes\"/${sdc}=\"no\"/g" "/etc.defaults/synoinfo.conf" + setting="$(get_key_value /etc.defaults/synoinfo.conf $sdc)" + if [[ $setting == "no" ]]; then + echo -e "\nDisabled support disk compatibility." + fi + fi +else + if [[ $setting == "no" ]]; then + # Enable support_disk_compatibility + sed -i "s/${sdc}=\"no\"/${sdc}=\"yes\"/g" "/etc.defaults/synoinfo.conf" + setting="$(get_key_value /etc.defaults/synoinfo.conf $sdc)" + if [[ $setting == "yes" ]]; then + echo -e "\nRe-enabled support disk compatibility." + fi + fi +fi + + +# Edit synoinfo.conf to prevent DB updates +#if [[ $nodbupdate == "yes" ]]; then # For future use + file=/etc.defaults/synoinfo.conf + if [[ -f $file ]]; then + # Backup synoinfo.conf if needed + if [[ ! -f "$file.bak" ]]; then + if cp "$file" "$file.bak"; then + echo "Backed up synoinfo.conf to $(basename -- "${file}").bak" + else + echo -e "\e[41m ERROR:\e[0m Failed to backup $(basename -- "${file}")!" + exit 6 + fi + fi + + url=$(get_key_value "$file" drive_db_test_url) # returns a linefeed if key doesn't exist + if [[ ! $url ]]; then + # Add drive_db_test_url=127.0.0.1 + echo "drive_db_test_url=127.0.0.1" >> "$file" + disabled="yes" + elif [[ $url != "127.0.0.1" ]]; then + # Edit drive_db_test_url= + sed -i "s/drive_db_test_url=$url/drive_db_test_url=127.0.0.1/g" "$file" + disabled="yes" + fi + + url=$(get_key_value "$file" drive_db_test_url) + if [[ $disabled == "yes" ]]; then + if [[ $url == "127.0.0.1" ]]; then + echo "Disabled drive db auto updates." + else + echo -e "\e[41m ERROR:\e[0m Failed to disable drive db auto updates!" + fi + fi + fi +#fi + + # Show the changes if [[ ${showedits,,} == "yes" ]]; then lines=$(((db2Edits *12) +4)) if [[ $db1Edits -gt "0" ]]; then - #echo -e "\nChanges to $(basename -- "$db1")" echo -e "\nChanges to ${Cyan}$(basename -- "$db1")${Off}" - #jq . "$db1" # nice colorized json format but displays whole file jq . "$db1" | tail -n "$lines" # show last 20 lines per edit fi if [[ $db2Edits -gt "0" ]]; then - #echo -e "\nChanges to $(basename -- "$db2")" echo -e "\nChanges to ${Cyan}$(basename -- "$db2")${Off}" - #jq . "$db2" | tail -n $((db2Edits *16)) # show last 20 lines per edit jq . "$db2" | tail -n "$lines" # show last 20 lines per edit fi fi +echo -e "\nYou may need to ${Cyan}reboot the Synology${Off} to see the changes." + exit From a0322474c343428ef510f0191774818bbcfbd42a Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 10 Mar 2023 16:09:22 +1100 Subject: [PATCH 03/24] Update syno_hdd_db.sh Fixed SAS drives --- syno_hdd_db.sh | 185 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 132 insertions(+), 53 deletions(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index 9a1b6c3..781c0ef 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -33,6 +33,15 @@ # It's also parsed and checked and probably in some cases it could be more critical to patch that one instead. # DONE +# Force DSM to check disk compatability so reboot not needed (DSM 6 may still need a reboot). +# +# Changed SAS drive firmware version detection to use smartctl to support SAS drives that hdparm doesn't work with. +# +# Fixed DSM 6 issue when DSM 6 has the old db file format. +# +# Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). +# +# # Add support for SAS drives. # # Get HDD/SSD/SAS drive model number with smartctl instead of hdparm. @@ -46,7 +55,7 @@ # Optionally disable "support_disk_compatibility". -scriptver="1.1.9" +scriptver="1.1.11" # Check latest release with GitHub API get_latest_release() { @@ -74,7 +83,6 @@ while getopts "sfn" option; do case ${option,,,} in s) showedits=yes - #echo showedits # debug ;; n) nodbupdate=yes # For future use @@ -105,7 +113,7 @@ fi # Check script is running as root if [[ $( whoami ) != "root" ]]; then - echo -e "\e[41m ERROR:\e[0m This script must be run as root or sudo!" + echo -e "\e[41m ERROR \e[0m This script must be run as root or sudo!" exit 1 fi @@ -121,6 +129,7 @@ getModel() { #echo "Model: $hdmodel" # debug # Brands that return "BRAND " and need "BRAND " removed. + # Smartmontools database in /var/lib/smartmontools/drivedb.db hdmodel=${hdmodel#"WDC "} # Remove "WDC " from start of model name hdmodel=${hdmodel#"HGST "} # Remove "HGST " from start of model name hdmodel=${hdmodel#"TOSHIBA "} # Remove "TOSHIBA " from start of model name @@ -139,7 +148,7 @@ getModel() { } getFwVersion() { - if [[ $2 == "sas" ]]; then + if smartctl -i "$1" | grep -i sas >/dev/null; then # hdparm does not work with some SAS drives fwrev=$(smartctl -i "$1" | grep -i "Firmware Version:" | awk '{print $3}') if [[ ! $hdmodel ]]; then @@ -153,7 +162,7 @@ getFwVersion() { } getNVMeModel() { - nvmemodel=$(cat $1/model) + nvmemodel=$(cat "$1"/model) shopt -s extglob nvmemodel=${nvmemodel/#*([[:space:]])} # Remove leading spaces nvmemodel=${nvmemodel/%*([[:space:]])} # Remove trailing spaces @@ -162,14 +171,14 @@ getNVMeModel() { } getNVMeFwVersion() { - nvmefw=$(cat $1/firmware_rev) + nvmefw=$(cat "$1"/firmware_rev) nvmefw=$(echo "$nvmefw" | xargs) # trim leading and trailing white space #echo "NVMe Firmware: $nvmefw" # debug } -for d in `cat /proc/partitions | awk '{print $4}'`; do - if [ ! -e /dev/$d ]; then +for d in $(cat /proc/partitions | awk '{print $4}'); do + if [ ! -e /dev/"$d" ]; then continue; fi #echo $d # debug @@ -188,12 +197,7 @@ for d in `cat /proc/partitions | awk '{print $4}'`; do if [[ $d =~ (sas|sata)[0-9][0-9]?[0-9]?$ ]]; then #echo -e "\n$d" # debug getModel "/dev/$d" - if [[ $d =~ (sas)[0-9][0-9]?[0-9]?$ ]]; then - # hdparm does not work with some SAS drives - getFwVersion "/dev/$d" "sas" - else - getFwVersion "/dev/$d" - fi + getFwVersion "/dev/$d" if [[ $hdmodel ]] && [[ $fwrev ]]; then hdparm+=("${hdmodel},${fwrev}") fi @@ -202,7 +206,7 @@ for d in `cat /proc/partitions | awk '{print $4}'`; do nvme*) if [[ $d =~ nvme[0-9][0-9]?n[0-9][0-9]?$ ]]; then #echo -e "\n$d" # debug - n=n$(printf "$d" | cut -d "n" -f 2) + n=n$(printf "%s" "$d" | cut -d "n" -f 2) getNVMeModel "/sys/class/nvme/$n" getNVMeFwVersion "/sys/class/nvme/$n" if [[ $nvmemodel ]] && [[ $nvmefw ]]; then @@ -223,7 +227,7 @@ fi # Check hdds array isn't empty if [[ ${#hdds[@]} -eq "0" ]]; then - echo -e "\e[41m ERROR:\e[0m No drives found!" && exit 2 + echo -e "\e[41m ERROR \e[0m No drives found!" && exit 2 else echo "HDD/SSD models found: ${#hdds[@]}" num="0" @@ -262,8 +266,23 @@ fi db1="/var/lib/disk-compatibility/${model}_host${version}.db" db2="/var/lib/disk-compatibility/${model}_host${version}.db.new" -if [[ ! -f "$db1" ]]; then echo -e "\e[41m ERROR:\e[0m $db1 not found!" && exit 3; fi -if [[ ! -f "$db2" ]]; then echo -e "\e[41m ERROR:\e[0m $db2 not found!" && exit 4; fi +if [[ ! -f "$db1" ]]; then echo -e "\e[41m ERROR \e[0m $db1 not found!" && exit 3; fi +#if [[ ! -f "$db2" ]]; then echo -e "\e[41m ERROR \e[0m $db2 not found!" && exit 4; fi +# new installs don't have a .db.new file + + +# Detect drive db type +if grep -F '{"disk_compatbility_info":' "$db1" >/dev/null; then + # DSM 7 drive db files start with {"disk_compatbility_info": + dbtype=7 +elif grep -F '{"success":1,"list":[' "$db1" >/dev/null; then + # DSM 6 drive db files start with {"success":1,"list":[ + dbtype=6 +else + echo -e "\e[41m ERROR \e[0m Unknown database type $(basename -- "${db1}")!" + exit 7 +fi +#echo "dbtype: $dbtype" # debug # Backup database file if needed @@ -271,7 +290,7 @@ if [[ ! -f "$db1.bak" ]]; then if cp "$db1" "$db1.bak"; then echo -e "Backed up database to $(basename -- "${db1}").bak\n" else - echo -e "\e[41m ERROR:\e[0m Failed to backup $(basename -- "${db1}")!" + echo -e "\e[41m ERROR \e[0m Failed to backup $(basename -- "${db1}")!" exit 5 fi fi @@ -280,6 +299,7 @@ fi # Shell Colors Yellow='\e[0;33m' Cyan='\e[0;36m' +Red='\e[0;31m' Off=$'\e[0m' function updatedb() { @@ -294,27 +314,52 @@ function updatedb() { if grep "$hdmodel" "$2" >/dev/null; then echo -e "${Yellow}$hdmodel${Off} already exists in ${Cyan}$(basename -- "$2")${Off}" else - # Don't need to add firmware version? - fwstrng=\"$fwrev\" - fwstrng="$fwstrng":{\"compatibility_interval\":[{\"compatibility\":\"support\",\"not_yet_rolling_status\" - fwstrng="$fwstrng":\"support\",\"fw_dsm_update_status_notify\":false,\"barebone_installable\":true}]}, - - default=\"default\" - default="$default":{\"compatibility_interval\":[{\"compatibility\":\"support\",\"not_yet_rolling_status\" - default="$default":\"support\",\"fw_dsm_update_status_notify\":false,\"barebone_installable\":true}]}}} - - #if sed -i "s/}}}/}},\"$hdmodel\":{$fwstrng$default/g" "$2"; then # Don't need to add firmware version? - if sed -i "s/}}}/}},\"$hdmodel\":{$default/g" "$2"; then - #echo "Added $hdmodel to $(basename -- "$2")" - echo -e "Added ${Yellow}$hdmodel${Off} to ${Cyan}$(basename -- "$2")${Off}" - if [[ $2 == "$db1" ]]; then - db1Edits=$((db1Edits +1)) - elif [[ $2 == "$db2" ]]; then - db2Edits=$((db2Edits +1)) + if [[ $dbtype -gt "6" ]];then + # Don't need to add firmware version? + fwstrng=\"$fwrev\" + fwstrng="$fwstrng":{\"compatibility_interval\":[{\"compatibility\":\"support\",\"not_yet_rolling_status\" + fwstrng="$fwstrng":\"support\",\"fw_dsm_update_status_notify\":false,\"barebone_installable\":true}]}, + + default=\"default\" + default="$default":{\"compatibility_interval\":[{\"compatibility\":\"support\",\"not_yet_rolling_status\" + default="$default":\"support\",\"fw_dsm_update_status_notify\":false,\"barebone_installable\":true}]}}} + + #if sed -i "s/}}}/}},\"$hdmodel\":{$fwstrng$default/" "$2"; then # Don't need to add firmware version? + if sed -i "s/}}}/}},\"$hdmodel\":{$default/" "$2"; then + echo -e "Added ${Yellow}$hdmodel${Off} to ${Cyan}$(basename -- "$2")${Off}" + if [[ $2 == "$db1" ]]; then + db1Edits=$((db1Edits +1)) + elif [[ $2 == "$db2" ]]; then + db2Edits=$((db2Edits +1)) + fi + else + echo -e "\n\e[41m ERROR \e[0m Failed to update v7 $(basename -- "$2")${Off}" + exit 6 fi else - echo -e "\n\e[41m ERROR: Failed to update $(basename -- "$2")${Off}" - exit 6 + # example: + # {"model":"WD60EFRX-68MYMN1","firmware":"82.00A82","rec_intvl":[1]}, + string="{\"model\":\"${hdmodel}\",\"firmware\":\"${fwrev}\",\"rec_intvl\":\[1\]}," + # {"success":1,"list":[ + startstring="{\"success\":1,\"list\":\[" + + #echo "$startstring" # debug + #echo "$string" # debug + #echo # debug + + # example: + # {"success":1,"list":[{"model":"WD60EFRX-68MYMN1","firmware":"82.00A82","rec_intvl":[1]}, + if sed -ir "s/$startstring/$startstring$string/" "$2"; then + echo -e "Added ${Yellow}$hdmodel${Off} to ${Cyan}$(basename -- "$2")${Off}" + if [[ $2 == "$db1" ]]; then + db1Edits=$((db1Edits +1)) + elif [[ $2 == "$db2" ]]; then + db2Edits=$((db2Edits +1)) + fi + else + echo -e "\n\e[41m ERROR \e[0m Failed to update $(basename -- "$2")${Off}" + exit 8 + fi fi fi } @@ -323,7 +368,9 @@ function updatedb() { num="0" while [[ $num -lt "${#hdds[@]}" ]]; do updatedb "${hdds[$num]}" "$db1" - updatedb "${hdds[$num]}" "$db2" + if [[ -f "$db2" ]]; then + updatedb "${hdds[$num]}" "$db2" + fi num=$((num +1)) done @@ -331,7 +378,9 @@ done num="0" while [[ $num -lt "${#nvmes[@]}" ]]; do updatedb "${nvmes[$num]}" "$db1" - updatedb "${nvmes[$num]}" "$db2" + if [[ -f "$db2" ]]; then + updatedb "${nvmes[$num]}" "$db2" + fi num=$((num +1)) done @@ -342,7 +391,7 @@ setting="$(get_key_value /etc.defaults/synoinfo.conf $sdc)" if [[ $force == "yes" ]]; then if [[ $setting == "yes" ]]; then # Disable support_disk_compatibility - sed -i "s/${sdc}=\"yes\"/${sdc}=\"no\"/g" "/etc.defaults/synoinfo.conf" + sed -i "s/${sdc}=\"yes\"/${sdc}=\"no\"/" "/etc.defaults/synoinfo.conf" setting="$(get_key_value /etc.defaults/synoinfo.conf $sdc)" if [[ $setting == "no" ]]; then echo -e "\nDisabled support disk compatibility." @@ -351,7 +400,7 @@ if [[ $force == "yes" ]]; then else if [[ $setting == "no" ]]; then # Enable support_disk_compatibility - sed -i "s/${sdc}=\"no\"/${sdc}=\"yes\"/g" "/etc.defaults/synoinfo.conf" + sed -i "s/${sdc}=\"no\"/${sdc}=\"yes\"/" "/etc.defaults/synoinfo.conf" setting="$(get_key_value /etc.defaults/synoinfo.conf $sdc)" if [[ $setting == "yes" ]]; then echo -e "\nRe-enabled support disk compatibility." @@ -369,7 +418,7 @@ fi if cp "$file" "$file.bak"; then echo "Backed up synoinfo.conf to $(basename -- "${file}").bak" else - echo -e "\e[41m ERROR:\e[0m Failed to backup $(basename -- "${file}")!" + echo -e "\e[41m ERROR \e[0m Failed to backup $(basename -- "${file}")!" exit 6 fi fi @@ -381,7 +430,7 @@ fi disabled="yes" elif [[ $url != "127.0.0.1" ]]; then # Edit drive_db_test_url= - sed -i "s/drive_db_test_url=$url/drive_db_test_url=127.0.0.1/g" "$file" + sed -i "s/drive_db_test_url=$url/drive_db_test_url=127.0.0.1/" "$file" disabled="yes" fi @@ -390,7 +439,7 @@ fi if [[ $url == "127.0.0.1" ]]; then echo "Disabled drive db auto updates." else - echo -e "\e[41m ERROR:\e[0m Failed to disable drive db auto updates!" + echo -e "\e[41m ERROR \e[0m Failed to disable drive db auto updates!" fi fi fi @@ -399,18 +448,48 @@ fi # Show the changes if [[ ${showedits,,} == "yes" ]]; then - lines=$(((db2Edits *12) +4)) - if [[ $db1Edits -gt "0" ]]; then - echo -e "\nChanges to ${Cyan}$(basename -- "$db1")${Off}" - jq . "$db1" | tail -n "$lines" # show last 20 lines per edit + if [[ $dbtype -gt "6" ]];then + # Show last 12 lines per drive + 4 + lines=$(((db1Edits *12) +4)) + if [[ $db1Edits -gt "0" ]]; then + echo -e "\nChanges to ${Cyan}$(basename -- "$db1")${Off}" + jq . "$db1" | tail -n "$lines" + fi + if [[ $db2Edits -gt "0" ]]; then + echo -e "\nChanges to ${Cyan}$(basename -- "$db2")${Off}" + jq . "$db2" | tail -n "$lines" + fi + else + # Show first 8 lines per drive + 2 + lines=$(((db1Edits *8) +2)) + if [[ $db1Edits -gt "0" ]]; then + echo -e "\nChanges to ${Cyan}$(basename -- "$db1")${Off}" + jq . "$db1" | head -n "$lines" + fi + if [[ $db2Edits -gt "0" ]]; then + echo -e "\nChanges to ${Cyan}$(basename -- "$db2")${Off}" + jq . "$db2" | head -n "$lines" + fi fi - if [[ $db2Edits -gt "0" ]]; then - echo -e "\nChanges to ${Cyan}$(basename -- "$db2")${Off}" - jq . "$db2" | tail -n "$lines" # show last 20 lines per edit +fi + + +# Make Synology check disk compatability +/usr/syno/sbin/synostgdisk --check-all-disks-compatibility +status=$? +if [[ $status -eq "0" ]]; then + echo -e "\nDSM successfully checked disk compatibility." +else + # Ignore DSM 6 as it returns 255 for "synostgdisk --check-all-disks-compatibility" + if [[ $dsm -gt "6" ]]; then + echo -e "\nDSM ${Red}failed${Off} to check disk compatibility with exit code $status" + echo -e "\nYou may need to ${Cyan}reboot the Synology${Off} to see the changes." fi fi -echo -e "\nYou may need to ${Cyan}reboot the Synology${Off} to see the changes." +if [[ $dsm -eq "6" ]]; then + echo -e "\nYou may need to ${Cyan}reboot the Synology${Off} to see the changes." +fi exit From 96b6a88f322b706b06838798172177f4676c64ec Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 10 Mar 2023 17:07:52 +1100 Subject: [PATCH 04/24] Update syno_hdd_db.sh --- syno_hdd_db.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index 781c0ef..e49e8e8 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -151,7 +151,7 @@ getFwVersion() { if smartctl -i "$1" | grep -i sas >/dev/null; then # hdparm does not work with some SAS drives fwrev=$(smartctl -i "$1" | grep -i "Firmware Version:" | awk '{print $3}') - if [[ ! $hdmodel ]]; then + if [[ ! $fwrev ]]; then fwrev=$(smartctl -i "$1" | grep -i "Revision:" | awk '{print $2}') fi else From 8d3433f0c63395a1328ad88518d4212e80a538dd Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 12:01:39 +1100 Subject: [PATCH 05/24] Update syno_hdd_db.sh - Added support for M.2 SATA drives. - Changed method of getting drive and firmware version so script is faster and easier to maintain. No longer using smartctl or hdparm. - Changed to skip M.2 drives if run with the -m2 flag. - Changed SAS drive firmware version detection to use smartctl to support SAS drives that hdparm doesn't work with. - Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). --- syno_hdd_db.sh | 203 ++++++++++++++++++++++++------------------------- 1 file changed, 99 insertions(+), 104 deletions(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index e49e8e8..ee04219 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -33,15 +33,22 @@ # It's also parsed and checked and probably in some cases it could be more critical to patch that one instead. # DONE -# Force DSM to check disk compatability so reboot not needed (DSM 6 may still need a reboot). +# Added support for M.2 SATA drives. # -# Changed SAS drive firmware version detection to use smartctl to support SAS drives that hdparm doesn't work with. +# Changed method of getting drive and firmware version so script is faster and easier to maintain. +# - No longer using smartctl or hdparm. # -# Fixed DSM 6 issue when DSM 6 has the old db file format. +# Changed to skip M.2 drives if run with the -m2 flag. +# +# Changed SAS drive firmware version detection to use smartctl to support SAS drives that hdparm doesn't work with. # # Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). # # +# Force DSM to check disk compatibility so reboot not needed (DSM 6 may still need a reboot). +# +# Fixed DSM 6 issue when DSM 6 has the old db file format. +# # Add support for SAS drives. # # Get HDD/SSD/SAS drive model number with smartctl instead of hdparm. @@ -55,7 +62,7 @@ # Optionally disable "support_disk_compatibility". -scriptver="1.1.11" +scriptver="1.1.10" # Check latest release with GitHub API get_latest_release() { @@ -77,7 +84,7 @@ fi # Check for flags with getopts OPTERR=0 -while getopts "sfn" option; do +while getopts "sfnm" option; do # Need to ensure any other long flags do not contain s, n, or f if [[ ! ${#option} -gt "1" ]]; then case ${option,,,} in @@ -87,8 +94,11 @@ while getopts "sfn" option; do n) nodbupdate=yes # For future use ;; + m) + m2=no # Don't add M.2 drives to db files + ;; f) - force=yes + force=yes # Disable "support_disk_compatibility" ;; *) ;; @@ -113,104 +123,85 @@ fi # Check script is running as root if [[ $( whoami ) != "root" ]]; then - echo -e "\e[41m ERROR \e[0m This script must be run as root or sudo!" + echo -e "\e[41mERROR\e[0m This script must be run as root or sudo!" exit 1 fi #------------------------------------------------------------------------------ -# Get list of installed SATA, SAS and NVMe drives - -getModel() { - hdmodel=$(smartctl -i "$1" | grep -i "Device Model:" | awk '{print $3 $4 $5}') - if [[ ! $hdmodel ]]; then - hdmodel=$(smartctl -i "$1" | grep -i "Product:" | awk '{print $2 $3 $4}') - fi - #echo "Model: $hdmodel" # debug - - # Brands that return "BRAND " and need "BRAND " removed. - # Smartmontools database in /var/lib/smartmontools/drivedb.db - hdmodel=${hdmodel#"WDC "} # Remove "WDC " from start of model name - hdmodel=${hdmodel#"HGST "} # Remove "HGST " from start of model name - hdmodel=${hdmodel#"TOSHIBA "} # Remove "TOSHIBA " from start of model name - - # Old drive brands - hdmodel=${hdmodel#"Hitachi "} # Remove "Hitachi " from start of model name - hdmodel=${hdmodel#"SAMSUNG "} # Remove "SAMSUNG " from start of model name - hdmodel=${hdmodel#"FUJISTU "} # Remove "FUJISTU " from start of model name - hdmodel=${hdmodel#"APPLE HDD "} # Remove "APPLE HDD " from start of model name - - shopt -s extglob - hdmodel=${hdmodel/#*([[:space:]])} # Remove leading spaces - hdmodel=${hdmodel/%*([[:space:]])} # Remove trailing spaces - shopt -u extglob - #echo "Model: $hdmodel" # debug -} - -getFwVersion() { - if smartctl -i "$1" | grep -i sas >/dev/null; then - # hdparm does not work with some SAS drives - fwrev=$(smartctl -i "$1" | grep -i "Firmware Version:" | awk '{print $3}') - if [[ ! $fwrev ]]; then - fwrev=$(smartctl -i "$1" | grep -i "Revision:" | awk '{print $2}') - fi - else - tmp=$(hdparm -i "$1" | grep Model) - fwrev=$(printf %s "$tmp" | cut -d"," -f 2 | cut -d"=" -f 2) - fi - #echo "Firmware: $fwrev" # debug -} - -getNVMeModel() { - nvmemodel=$(cat "$1"/model) - shopt -s extglob - nvmemodel=${nvmemodel/#*([[:space:]])} # Remove leading spaces - nvmemodel=${nvmemodel/%*([[:space:]])} # Remove trailing spaces - shopt -u extglob - #echo "NVMe Model: $nvmemodel" # debug -} - -getNVMeFwVersion() { - nvmefw=$(cat "$1"/firmware_rev) - nvmefw=$(echo "$nvmefw" | xargs) # trim leading and trailing white space - #echo "NVMe Firmware: $nvmefw" # debug -} - - -for d in $(cat /proc/partitions | awk '{print $4}'); do - if [ ! -e /dev/"$d" ]; then - continue; - fi +# Get list of installed SATA, SAS and M.2 NVMe/SATA drives + +#for d in $(ls /sys/block); do +for d in /sys/block/*; do +# if [ ! -e /dev/"$d" ]; then +# echo "Found /dev/$d" # debug +# continue; +# fi #echo $d # debug case "$d" in - hd*|sd*) - if [[ $d =~ [hs]d[a-z]{1,2}$ ]]; then - #echo -e "\n$d" # debug - getModel "/dev/$d" - getFwVersion "/dev/$d" + sd*|hd*) + if [[ $d =~ [hs]d[a-z]$ ]]; then + hdmodel=$(cat "/sys/block/$d/device/model") + hdmodel=$(printf "%s" "$hdmodel" | xargs) # trim leading and trailing white space + #echo "Model: '$hdmodel'" # debug + + fwrev=$(cat "/sys/block/$d/device/rev") + fwrev=$(printf "%s" "$fwrev" | xargs) # trim leading and trailing white space + #echo "Firmware: '$fwrev'" # debug + if [[ $hdmodel ]] && [[ $fwrev ]]; then - hdparm+=("${hdmodel},${fwrev}") + hdlist+=("${hdmodel},${fwrev}") fi fi ;; sas*|sata*) if [[ $d =~ (sas|sata)[0-9][0-9]?[0-9]?$ ]]; then - #echo -e "\n$d" # debug - getModel "/dev/$d" - getFwVersion "/dev/$d" + hdmodel=$(cat "/sys/block/$d/device/model") + hdmodel=$(printf "%s" "$hdmodel" | xargs) # trim leading and trailing white space + #echo "Model: '$hdmodel'" # debug + + fwrev=$(cat "/sys/block/$d/device/rev") + fwrev=$(printf "%s" "$fwrev" | xargs) # trim leading and trailing white space + #echo "Firmware: '$fwrev'" # debug + if [[ $hdmodel ]] && [[ $fwrev ]]; then - hdparm+=("${hdmodel},${fwrev}") + hdlist+=("${hdmodel},${fwrev}") fi fi ;; nvme*) if [[ $d =~ nvme[0-9][0-9]?n[0-9][0-9]?$ ]]; then - #echo -e "\n$d" # debug - n=n$(printf "%s" "$d" | cut -d "n" -f 2) - getNVMeModel "/sys/class/nvme/$n" - getNVMeFwVersion "/sys/class/nvme/$n" - if [[ $nvmemodel ]] && [[ $nvmefw ]]; then - nvmelist+=("${nvmemodel},${nvmefw}") + if [[ $m2 != "no" ]]; then + nvmemodel=$(cat "/sys/block/$d/device/model") + nvmemodel=$(printf "%s" "$nvmemodel" | xargs) # trim leading and trailing white space + #echo "NVMe Model: '$nvmemodel'" # debug + + nvmefw=$(cat "/sys/block/$d/device/firmware_rev") + nvmefw=$(printf "%s" "$nvmefw" | xargs) # trim leading and trailing white space + #echo "NVMe Firmware: '$nvmefw'" # debug + + if [[ $nvmemodel ]] && [[ $nvmefw ]]; then + nvmelist+=("${nvmemodel},${nvmefw}") + fi + fi + fi + ;; + nvc*) # M.2 SATA drives (in PCIe card only?) + #if [[ $d =~ nvc[0-9][0-9]?p[0-9][0-9]?$ ]]; then + if [[ $d =~ nvc[0-9][0-9]?$ ]]; then + if [[ $m2 != "no" ]]; then + nvmemodel=$(cat "/sys/block/$d/device/model") + nvmemodel=$(printf "%s" "$nvmemodel" | xargs) # trim leading and trailing white space + #echo "M.2 SATA Model: '$nvmemodel'" # debug + + #nvmefw=$(cat "/sys/block/$d/device/firmware_rev") + nvmefw=$(cat "/sys/block/$d/device/rev") + nvmefw=$(printf "%s" "$nvmefw" | xargs) # trim leading and trailing white space + #echo "M.2 SATA Firmware: '$nvmefw'" # debug + + if [[ $nvmemodel ]] && [[ $nvmefw ]]; then + nvmelist+=("${nvmemodel},${nvmefw}") + fi fi fi ;; @@ -218,16 +209,16 @@ for d in $(cat /proc/partitions | awk '{print $4}'); do done -# Sort hdparm array into new hdds array to remove duplicates -if [[ ${#hdparm[@]} -gt "0" ]]; then +# Sort hdlist array into new hdds array to remove duplicates +if [[ ${#hdlist[@]} -gt "0" ]]; then while IFS= read -r -d '' x; do hdds+=("$x") - done < <(printf "%s\0" "${hdparm[@]}" | sort -uz) + done < <(printf "%s\0" "${hdlist[@]}" | sort -uz) fi # Check hdds array isn't empty if [[ ${#hdds[@]} -eq "0" ]]; then - echo -e "\e[41m ERROR \e[0m No drives found!" && exit 2 + echo -e "\e[41mERROR\e[0m No drives found!" && exit 2 else echo "HDD/SSD models found: ${#hdds[@]}" num="0" @@ -248,9 +239,11 @@ fi # Check nvmes array isn't empty if [[ ${#nvmes[@]} -eq "0" ]]; then - echo -e "No NVMe drives found\n" + if [[ $m2 != "no" ]]; then + echo -e "No M.2 NVMe/SATA drives found\n" + fi else - echo "NVMe drive models found: ${#nvmes[@]}" + echo "M.2 NVMe/SATA drive models found: ${#nvmes[@]}" num="0" while [[ $num -lt "${#nvmes[@]}" ]]; do echo "${nvmes[num]}" @@ -266,8 +259,8 @@ fi db1="/var/lib/disk-compatibility/${model}_host${version}.db" db2="/var/lib/disk-compatibility/${model}_host${version}.db.new" -if [[ ! -f "$db1" ]]; then echo -e "\e[41m ERROR \e[0m $db1 not found!" && exit 3; fi -#if [[ ! -f "$db2" ]]; then echo -e "\e[41m ERROR \e[0m $db2 not found!" && exit 4; fi +if [[ ! -f "$db1" ]]; then echo -e "\e[41mERROR\e[0m $db1 not found!" && exit 3; fi +#if [[ ! -f "$db2" ]]; then echo -e "\e[41mERROR\e[0m $db2 not found!" && exit 4; fi # new installs don't have a .db.new file @@ -279,7 +272,7 @@ elif grep -F '{"success":1,"list":[' "$db1" >/dev/null; then # DSM 6 drive db files start with {"success":1,"list":[ dbtype=6 else - echo -e "\e[41m ERROR \e[0m Unknown database type $(basename -- "${db1}")!" + echo -e "\e[41mERROR\e[0m Unknown database type $(basename -- "${db1}")!" exit 7 fi #echo "dbtype: $dbtype" # debug @@ -290,7 +283,7 @@ if [[ ! -f "$db1.bak" ]]; then if cp "$db1" "$db1.bak"; then echo -e "Backed up database to $(basename -- "${db1}").bak\n" else - echo -e "\e[41m ERROR \e[0m Failed to backup $(basename -- "${db1}")!" + echo -e "\e[41mERROR\e[0m Failed to backup $(basename -- "${db1}")!" exit 5 fi fi @@ -303,8 +296,8 @@ Red='\e[0;31m' Off=$'\e[0m' function updatedb() { - hdmodel=$(printf %s "$1" | cut -d"," -f 1) - fwrev=$(printf %s "$1" | cut -d"," -f 2) + hdmodel=$(printf "%s" "$1" | cut -d"," -f 1) + fwrev=$(printf "%s" "$1" | cut -d"," -f 2) #echo arg1 "$1" # debug #echo arg2 "$2" # debug @@ -333,13 +326,15 @@ function updatedb() { db2Edits=$((db2Edits +1)) fi else - echo -e "\n\e[41m ERROR \e[0m Failed to update v7 $(basename -- "$2")${Off}" + echo -e "\n\e[41mERROR\e[0m Failed to update v7 $(basename -- "$2")${Off}" exit 6 fi else # example: # {"model":"WD60EFRX-68MYMN1","firmware":"82.00A82","rec_intvl":[1]}, - string="{\"model\":\"${hdmodel}\",\"firmware\":\"${fwrev}\",\"rec_intvl\":\[1\]}," + # Don't need to add firmware version? + #string="{\"model\":\"${hdmodel}\",\"firmware\":\"${fwrev}\",\"rec_intvl\":\[1\]}," + string="{\"model\":\"${hdmodel}\",\"firmware\":\"\",\"rec_intvl\":\[1\]}," # {"success":1,"list":[ startstring="{\"success\":1,\"list\":\[" @@ -357,7 +352,7 @@ function updatedb() { db2Edits=$((db2Edits +1)) fi else - echo -e "\n\e[41m ERROR \e[0m Failed to update $(basename -- "$2")${Off}" + echo -e "\n\e[41mERROR\e[0m Failed to update $(basename -- "$2")${Off}" exit 8 fi fi @@ -374,7 +369,7 @@ while [[ $num -lt "${#hdds[@]}" ]]; do num=$((num +1)) done -# NVMe drives +# M.2 NVMe/SATA drives num="0" while [[ $num -lt "${#nvmes[@]}" ]]; do updatedb "${nvmes[$num]}" "$db1" @@ -418,7 +413,7 @@ fi if cp "$file" "$file.bak"; then echo "Backed up synoinfo.conf to $(basename -- "${file}").bak" else - echo -e "\e[41m ERROR \e[0m Failed to backup $(basename -- "${file}")!" + echo -e "\e[41mERROR\e[0m Failed to backup $(basename -- "${file}")!" exit 6 fi fi @@ -439,7 +434,7 @@ fi if [[ $url == "127.0.0.1" ]]; then echo "Disabled drive db auto updates." else - echo -e "\e[41m ERROR \e[0m Failed to disable drive db auto updates!" + echo -e "\e[41mERROR\e[0m Failed to disable drive db auto updates!" fi fi fi @@ -474,7 +469,7 @@ if [[ ${showedits,,} == "yes" ]]; then fi -# Make Synology check disk compatability +# Make Synology check disk compatibility /usr/syno/sbin/synostgdisk --check-all-disks-compatibility status=$? if [[ $status -eq "0" ]]; then From 76caf0fdc9dfdb45d0c11365a855bcae284f7e98 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 12:09:47 +1100 Subject: [PATCH 06/24] Create CHANGES.txt --- CHANGES.txt | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 CHANGES.txt diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..afc2d20 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,49 @@ +v1.1.11 +- Added support for M.2 SATA drives. +- Can now skip processing M.2 drives by running script with the -m2 flag. +- Changed method of getting drive and firmware version so script is faster and easier to maintain. No longer using smartctl or hdparm. +- Changed SAS drive firmware version detection to support SAS drives that hdparm doesn't work with. +- Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). + +v1.1.10 +- Now makes DSM recheck disk compatibility so reboot not needed (DSM 7 only). +- Fixed DSM 6 bug when DSM 6 used the old db file format. + +v1.1.9 +- Added support for SAS drives. +- Now gets HDD/SSD/SAS drive model number with smartctl instead of hdparm. + +v1.1.8 +- Now prevents DSM auto updating the drive database. +- Disable "support_disk_compatibility" (that was added in v1.0.6) is now optional. + - Run script with -f or -force to disable "support_disk_compatibility". + - If run without -f or -force "support_disk_compatibility" is re-enabled. + +v1.0.7 +Added message if newer script version is available. + +v1.0.6 +Added 2nd method of disabling disk compatibility to solve issue #1 and #4 for the few people where the original method didn't work. + +v1.0.5 +Changed to avoid issue #2 + +v1.0.4 +Now backs up the database file if there is no backup already. + +v1.0.3 +Changed to avoid avoid error messages from previous change to search for sda and sata# drives in DSM 6 and DSM 7. +- /dev/sata*: No such file or directory +- /dev/sd*: No such file or directory + +v1.0.2 +Improved formatting when listing found drives. + +v1.0.1 +Fixed issue where drives weren't detected if: +- NAS had been updated from DSM 6 to DSM 7 and still used sda, sdb etc. +- Models like the DVA3219 that use sata# even in DSM 6. + +v1.0.0 +Initial release. + From 5c27a6a7ecf8a36d21c9ffbb297f527e38e8c632 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 12:38:22 +1100 Subject: [PATCH 07/24] Update syno_hdd_db.sh --- syno_hdd_db.sh | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index ee04219..0eaceef 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -35,12 +35,12 @@ # DONE # Added support for M.2 SATA drives. # +# Can now skip processing M.2 drives by running script with the -m2 flag. +# # Changed method of getting drive and firmware version so script is faster and easier to maintain. # - No longer using smartctl or hdparm. # -# Changed to skip M.2 drives if run with the -m2 flag. -# -# Changed SAS drive firmware version detection to use smartctl to support SAS drives that hdparm doesn't work with. +# Changed SAS drive firmware version detection to support SAS drives that hdparm doesn't work with. # # Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). # @@ -138,14 +138,14 @@ for d in /sys/block/*; do # continue; # fi #echo $d # debug - case "$d" in + case "$(basename -- "${d}")" in sd*|hd*) if [[ $d =~ [hs]d[a-z]$ ]]; then - hdmodel=$(cat "/sys/block/$d/device/model") + hdmodel=$(cat "$d/device/model") hdmodel=$(printf "%s" "$hdmodel" | xargs) # trim leading and trailing white space #echo "Model: '$hdmodel'" # debug - fwrev=$(cat "/sys/block/$d/device/rev") + fwrev=$(cat "$d/device/rev") fwrev=$(printf "%s" "$fwrev" | xargs) # trim leading and trailing white space #echo "Firmware: '$fwrev'" # debug @@ -154,13 +154,13 @@ for d in /sys/block/*; do fi fi ;; - sas*|sata*) + sata*|sas*) if [[ $d =~ (sas|sata)[0-9][0-9]?[0-9]?$ ]]; then - hdmodel=$(cat "/sys/block/$d/device/model") + hdmodel=$(cat "$d/device/model") hdmodel=$(printf "%s" "$hdmodel" | xargs) # trim leading and trailing white space #echo "Model: '$hdmodel'" # debug - fwrev=$(cat "/sys/block/$d/device/rev") + fwrev=$(cat "$d/device/rev") fwrev=$(printf "%s" "$fwrev" | xargs) # trim leading and trailing white space #echo "Firmware: '$fwrev'" # debug @@ -172,11 +172,11 @@ for d in /sys/block/*; do nvme*) if [[ $d =~ nvme[0-9][0-9]?n[0-9][0-9]?$ ]]; then if [[ $m2 != "no" ]]; then - nvmemodel=$(cat "/sys/block/$d/device/model") + nvmemodel=$(cat "$d/device/model") nvmemodel=$(printf "%s" "$nvmemodel" | xargs) # trim leading and trailing white space #echo "NVMe Model: '$nvmemodel'" # debug - nvmefw=$(cat "/sys/block/$d/device/firmware_rev") + nvmefw=$(cat "$d/device/firmware_rev") nvmefw=$(printf "%s" "$nvmefw" | xargs) # trim leading and trailing white space #echo "NVMe Firmware: '$nvmefw'" # debug @@ -190,12 +190,12 @@ for d in /sys/block/*; do #if [[ $d =~ nvc[0-9][0-9]?p[0-9][0-9]?$ ]]; then if [[ $d =~ nvc[0-9][0-9]?$ ]]; then if [[ $m2 != "no" ]]; then - nvmemodel=$(cat "/sys/block/$d/device/model") + nvmemodel=$(cat "$d/device/model") nvmemodel=$(printf "%s" "$nvmemodel" | xargs) # trim leading and trailing white space #echo "M.2 SATA Model: '$nvmemodel'" # debug - #nvmefw=$(cat "/sys/block/$d/device/firmware_rev") - nvmefw=$(cat "/sys/block/$d/device/rev") + #nvmefw=$(cat "$d/device/firmware_rev") + nvmefw=$(cat "$d/device/rev") nvmefw=$(printf "%s" "$nvmefw" | xargs) # trim leading and trailing white space #echo "M.2 SATA Firmware: '$nvmefw'" # debug @@ -240,10 +240,10 @@ fi # Check nvmes array isn't empty if [[ ${#nvmes[@]} -eq "0" ]]; then if [[ $m2 != "no" ]]; then - echo -e "No M.2 NVMe/SATA drives found\n" + echo -e "No M.2 drives found\n" fi else - echo "M.2 NVMe/SATA drive models found: ${#nvmes[@]}" + echo "M.2 drive models found: ${#nvmes[@]}" num="0" while [[ $num -lt "${#nvmes[@]}" ]]; do echo "${nvmes[num]}" From d45ae58e8418c7c0b0ccd44d89100fb7748fdc0f Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 16:29:49 +1100 Subject: [PATCH 08/24] Update syno_hdd_db.sh Fixed version check --- syno_hdd_db.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index 0eaceef..e3de69d 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -73,7 +73,8 @@ get_latest_release() { tag=$(get_latest_release "007revad/Synology_HDD_db") -if [[ ${tag:1} > "$scriptver" ]]; then +if ! printf "%s\n%s\n" "$tag" "$scriptver" | + sort --check --version-sort &> /dev/null ; then echo "There is a newer version of this script available." echo -e "Current version: ${scriptver}\nLatest version: ${tag:1}" echo "https://github.com/007revad/Synology_HDD_db/releases/latest" From 9f0f102df514f5e103ba7a01dc276d5e7f169692 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 16:30:38 +1100 Subject: [PATCH 09/24] Update CHANGES.txt --- CHANGES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.txt b/CHANGES.txt index afc2d20..ba5e3e8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,7 @@ v1.1.11 - Changed method of getting drive and firmware version so script is faster and easier to maintain. No longer using smartctl or hdparm. - Changed SAS drive firmware version detection to support SAS drives that hdparm doesn't work with. - Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). +- Fixed version check. v1.1.10 - Now makes DSM recheck disk compatibility so reboot not needed (DSM 7 only). From 0be26411e64b9702d18fb2a8dc6003dec3d00fc3 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:03:43 +1100 Subject: [PATCH 10/24] Update CHANGES.txt Fixed script version check --- CHANGES.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index ba5e3e8..a8b08fe 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,10 +1,11 @@ v1.1.11 +v1.1.11 - Added support for M.2 SATA drives. - Can now skip processing M.2 drives by running script with the -m2 flag. - Changed method of getting drive and firmware version so script is faster and easier to maintain. No longer using smartctl or hdparm. - Changed SAS drive firmware version detection to support SAS drives that hdparm doesn't work with. - Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). -- Fixed version check. +- Fixed script version check introduced in 1.0.7. v1.1.10 - Now makes DSM recheck disk compatibility so reboot not needed (DSM 7 only). From 33353d716d30d1107ec0c470707e8d61b83d8011 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:03:54 +1100 Subject: [PATCH 11/24] Update CHANGES.txt --- CHANGES.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index a8b08fe..e784b34 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,4 @@ v1.1.11 -v1.1.11 - Added support for M.2 SATA drives. - Can now skip processing M.2 drives by running script with the -m2 flag. - Changed method of getting drive and firmware version so script is faster and easier to maintain. No longer using smartctl or hdparm. From 2384cc9dff1e59b703f275cfddab4a59c476278b Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:06:49 +1100 Subject: [PATCH 12/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d2e9db5..ba0eb2e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # Synology HDD db ### Description -Add your HDD, SSD and NVMe drives to your Synology's compatible drive database. +Add your HDD, SSD and M.2 drives to your Synology's compatible drive database. The script works in DSM 7 and DSM 6. From 9df855b69f209c7855949667c9534730a9ac6b37 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:29:27 +1100 Subject: [PATCH 13/24] Update syno_hdd_db.sh - Added support for M.2 SATA drives. - Can now skip processing M.2 drives by running script with the -m2 flag. - Changed method of getting drive and firmware version so script is faster and easier to maintain. No longer using smartctl or hdparm. - Changed SAS drive firmware version detection to support SAS drives that hdparm doesn't work with. - Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). - Fixed script version check introduced in 1.0.7. --- syno_hdd_db.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index e3de69d..0b4158d 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -62,7 +62,7 @@ # Optionally disable "support_disk_compatibility". -scriptver="1.1.10" +scriptver="1.1.11" # Check latest release with GitHub API get_latest_release() { @@ -450,8 +450,7 @@ if [[ ${showedits,,} == "yes" ]]; then if [[ $db1Edits -gt "0" ]]; then echo -e "\nChanges to ${Cyan}$(basename -- "$db1")${Off}" jq . "$db1" | tail -n "$lines" - fi - if [[ $db2Edits -gt "0" ]]; then + elif [[ $db2Edits -gt "0" ]]; then echo -e "\nChanges to ${Cyan}$(basename -- "$db2")${Off}" jq . "$db2" | tail -n "$lines" fi @@ -461,8 +460,7 @@ if [[ ${showedits,,} == "yes" ]]; then if [[ $db1Edits -gt "0" ]]; then echo -e "\nChanges to ${Cyan}$(basename -- "$db1")${Off}" jq . "$db1" | head -n "$lines" - fi - if [[ $db2Edits -gt "0" ]]; then + elif [[ $db2Edits -gt "0" ]]; then echo -e "\nChanges to ${Cyan}$(basename -- "$db2")${Off}" jq . "$db2" | head -n "$lines" fi From d2042768581dbc0633e21b2051f310f1d8ac6e59 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Mon, 13 Mar 2023 17:31:02 +1100 Subject: [PATCH 14/24] Update syno_hdd_db.sh --- syno_hdd_db.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index 0b4158d..c8004ba 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -44,7 +44,6 @@ # # Removed error message and aborting if *.db.new not found (clean DSM installs don't have a *.db.new). # -# # Force DSM to check disk compatibility so reboot not needed (DSM 6 may still need a reboot). # # Fixed DSM 6 issue when DSM 6 has the old db file format. From b08c66be3b007ae7fb34c70cb16785edfbec4254 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 17 Mar 2023 12:58:18 +1100 Subject: [PATCH 15/24] Update syno_hdd_db.sh - Added support for M.2 drives on a PCI card, M2Dxx and E10G18-T1 etc. - Improved flags/options checking and added usage help. - Can now download the latest script version for you (if you have user home service enabled in DSM). - Now adds 'support_m2_pool="yes"' line for models that don't have support_m2_pool in synoinfo.conf to (hopefully) prevent losing your SSH created M2 volume when running this script on models that DSM 7.2 Beta does not list as supported for creating M2 volumes. - Changed Synology model detection to be more reliable (for models that came in different variations). - Changed checking drive_db_test_url setting to be more durable. --- syno_hdd_db.sh | 526 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 362 insertions(+), 164 deletions(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index c8004ba..fbd0d78 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -23,16 +23,31 @@ #-------------------------------------------------------------------------------------------------- # TODO +# Bypass M.2 volume lock for unsupported M.2 drives. +# # Detect if expansion unit(s) connected and get model(s) and edit expansion unit db files. # Or add support for specifying user's expansion unit model(s) as arguments. # Or maybe use the shotgun approach and update all expansion unit db files. # -# Add support for M.2 SATA and NVMe drives on a M2D17 PCI card. -# -# Maybe also edit the other disk compatibility DB in synoboot, used during boot time. +# Maybe also edit the other disk compatibility db in synoboot, used during boot time. # It's also parsed and checked and probably in some cases it could be more critical to patch that one instead. # DONE +# Added support for M.2 drives on a PCI card, M2Dxx and E10G18-T1 etc. +# +# Improved flags/options checking and added usage help. +# +# Can now download the latest script version for you (if you have user home service enabled in DSM). +# +# Now adds 'support_m2_pool="yes"' line for models that don't have support_m2_pool in synoinfo.conf +# +# Changed Synology model detection to be more reliable (for models that came in different variations). +# +# Changed checking drive_db_test_url setting to be more durable. +# +# +# Added check that M.2 volume support is enabled (on supported models). +# # Added support for M.2 SATA drives. # # Can now skip processing M.2 drives by running script with the -m2 flag. @@ -61,52 +76,88 @@ # Optionally disable "support_disk_compatibility". -scriptver="1.1.11" +scriptver="v1.1.15" +script=Synology_HDD_db +repo="007revad/Synology_HDD_db" -# Check latest release with GitHub API -get_latest_release() { - curl --silent "https://api.github.com/repos/$1/releases/latest" | - grep '"tag_name":' | # Get tag line - sed -E 's/.*"([^"]+)".*/\1/' # Pluck JSON value -} - -tag=$(get_latest_release "007revad/Synology_HDD_db") - -if ! printf "%s\n%s\n" "$tag" "$scriptver" | - sort --check --version-sort &> /dev/null ; then - echo "There is a newer version of this script available." - echo -e "Current version: ${scriptver}\nLatest version: ${tag:1}" - echo "https://github.com/007revad/Synology_HDD_db/releases/latest" - echo "" - sleep 10 -fi +# Shell Colors +#Black='\e[0;30m' +Red='\e[0;31m' +#Green='\e[0;32m' +Yellow='\e[0;33m' +#Blue='\e[0;34m' +#Purple='\e[0;35m' +Cyan='\e[0;36m' +#White='\e[0;37m' +Error='\e[41m' +Off='\e[0m' + + +usage(){ + echo -e "\nUsage: $(basename $0) [options]\n" + echo "Options:" + echo " -s, --showedits Show the edits made to host db file(s)" + echo " -n, --noupdate Prevent DSM updating the compatible drive databases" + echo " -m, --m2 Don't process M.2 drives" + echo " -f, --force Force DSM to not check drive compatibility" + echo " -r, --ram Disable memory compatibility checking" + echo -e " -h, --help Show this help message\n" + exit +} -# Check for flags with getopts -OPTERR=0 -while getopts "sfnm" option; do - # Need to ensure any other long flags do not contain s, n, or f - if [[ ! ${#option} -gt "1" ]]; then - case ${option,,,} in - s) +# Check for flags with getopt +options="$(getopt -o abcdefghijklmnopqrstuvwxyz0123456789 -a \ + -l showedits,noupdate,m2,force,ram,help -- "$@")" +if [[ $? -eq "0" ]]; then + eval set -- "$options" + while true; do + case "${1,,}" in + -s|--showedits) # Show edits done to host db file showedits=yes ;; - n) - nodbupdate=yes # For future use + -n|--nodbupdate) # Disable disk compatibility db updates + nodbupdate=yes + ;; + -m|--m2) # Don't add M.2 drives to db files + m2=no + ;; + -f|--force) # Disable "support_disk_compatibility" + force=yes ;; - m) - m2=no # Don't add M.2 drives to db files + -r|--ram) # Include memory compatibility + ram=yes ;; - f) - force=yes # Disable "support_disk_compatibility" + -h|--help) # Show usage options + usage ;; - *) + --) + shift + break + ;; + *) # Show usage options + echo "Invalid option '$1'" + usage "$1" ;; esac - fi -done + shift + done +fi + + +# Check script is running as root +if [[ $( whoami ) != "root" ]]; then + echo -e "${Error}ERROR${Off} This script must be run as root or sudo!" + exit 1 +fi +# Get DSM major version +dsm=$(get_key_value /etc.defaults/VERSION majorversion) +if [[ $dsm -gt "6" ]]; then + version="_v$dsm" +fi +# Get Synology model model=$(cat /proc/sys/kernel/syno_hw_version) model=${model,,} # convert to lower case @@ -115,74 +166,133 @@ if [[ $model =~ '-j'$ ]]; then model=${model%??} # remove last two chars fi -# Get DSM major version -dsm=$(get_key_value /etc.defaults/VERSION majorversion) -if [[ $dsm -gt "6" ]]; then - version="_v$dsm" + +#------------------------------------------------------------------------------ +# Check latest release with GitHub API + +get_latest_release() { + curl --silent "https://api.github.com/repos/$1/releases/latest" | + grep '"tag_name":' | # Get tag line + sed -E 's/.*"([^"]+)".*/\1/' # Pluck JSON value +} + +tag=$(get_latest_release "007revad/Synology_HDD_db") +shorttag="${tag:1}" + +if [[ $HOME =~ /var/services/* ]]; then + shorthome=${HOME:14} +else + shorthome="$HOME" fi -# Check script is running as root -if [[ $( whoami ) != "root" ]]; then - echo -e "\e[41mERROR\e[0m This script must be run as root or sudo!" - exit 1 +if ! printf "%s\n%s\n" "$tag" "$scriptver" | + sort --check --version-sort &> /dev/null ; then + echo -e "${Cyan}There is a newer version of this script available.${Off}" + echo -e "Current version: ${scriptver}\nLatest version: $tag" + if [[ ! -d $HOME ]]; then + # Can't download to home + echo "https://github.com/$repo/releases/latest" + sleep 10 + elif [[ -f $HOME/$script-$shorttag.tar.gz ]]; then + # Latest version tar.gz in home but they're using older version + echo "https://github.com/$repo/releases/latest" + sleep 10 + else + echo -e "${Cyan}Do you want to download $tag now?${Off} {y/n]" + read -r -t 30 reply + if [[ ${reply,,} == "y" ]]; then + if ! curl -LJO "https://github.com/$repo/archive/refs/tags/$tag.tar.gz"; then + echo -e "${Error}ERROR ${Off} Failed to download $script-$shorttag.tar.gz!" + else + if [[ -f $HOME/$script-$shorttag.tar.gz ]]; then + if ! tar -xf "$HOME/$script-$shorttag.tar.gz"; then + echo -e "${Error}ERROR ${Off} Failed to extract $script-$shorttag.tar.gz!" + else + if ! rm "$HOME/$script-$shorttag.tar.gz"; then + echo -e "${Error}ERROR ${Off} Failed to delete downloaded $script-$shorttag.tar.gz!" + else + echo -e "\n$tag and changes.txt are in ${Cyan}$shorthome/$script-$shorttag${Off}" + echo -e "${Cyan}Do you want to stop this script so you can run the new one?${Off} {y/n]" + read -r -t 30 reply + if [[ ${reply,,} == "y" ]]; then exit; fi + fi + fi + else + echo -e "${Error}ERROR ${Off} $shorthome/$script-$shorttag.tar.gz not found!" + #ls $HOME/ | grep "$script" # debug + fi + fi + fi + fi fi #------------------------------------------------------------------------------ # Get list of installed SATA, SAS and M.2 NVMe/SATA drives -#for d in $(ls /sys/block); do +getdriveinfo() { + # Get drive model and firmware version + hdmodel=$(cat "$1/device/model") + hdmodel=$(printf "%s" "$hdmodel" | xargs) # trim leading and trailing white space + + fwrev=$(cat "$1/device/rev") + fwrev=$(printf "%s" "$fwrev" | xargs) # trim leading and trailing white space + + if [[ $hdmodel ]] && [[ $fwrev ]]; then + hdlist+=("${hdmodel},${fwrev}") + fi +} + +getm2info() { + nvmemodel=$(cat "$1/device/model") + nvmemodel=$(printf "%s" "$nvmemodel" | xargs) # trim leading and trailing white space + if [[ $2 == "nvme" ]]; then + nvmefw=$(cat "$1/device/firmware_rev") + elif [[ $2 == "nvc" ]]; then + nvmefw=$(cat "$1/device/rev") + fi + nvmefw=$(printf "%s" "$nvmefw" | xargs) # trim leading and trailing white space + + if [[ $nvmemodel ]] && [[ $nvmefw ]]; then + nvmelist+=("${nvmemodel},${nvmefw}") + fi +} + +getcardmodel() { + # Get M.2 card model + cardmodel=$(synodisk --m2-card-model-get "$1") + if [[ $cardmodel =~ M2D[0-9][0-9] ]]; then + # M2 adaptor card + m2carddblist+=("${model}_${cardmodel,,}${version}.db") # M.2 card's db file + m2cardlist+=("$cardmodel") # M.2 card + elif [[ $cardmodel =~ E[0-9][0-9]+M.+ ]]; then + # Ethernet + M2 adaptor card + m2carddblist+=("${model}_${cardmodel,,}${version}.db") # M.2 card's db file + m2cardlist+=("$cardmodel") # M.2 card + fi +} + + for d in /sys/block/*; do -# if [ ! -e /dev/"$d" ]; then -# echo "Found /dev/$d" # debug -# continue; -# fi - #echo $d # debug case "$(basename -- "${d}")" in sd*|hd*) - if [[ $d =~ [hs]d[a-z]$ ]]; then - hdmodel=$(cat "$d/device/model") - hdmodel=$(printf "%s" "$hdmodel" | xargs) # trim leading and trailing white space - #echo "Model: '$hdmodel'" # debug - - fwrev=$(cat "$d/device/rev") - fwrev=$(printf "%s" "$fwrev" | xargs) # trim leading and trailing white space - #echo "Firmware: '$fwrev'" # debug - - if [[ $hdmodel ]] && [[ $fwrev ]]; then - hdlist+=("${hdmodel},${fwrev}") - fi + if [[ $d =~ [hs]d[a-z][a-z]?$ ]]; then + # Get drive model and firmware version + getdriveinfo "$d" fi ;; sata*|sas*) if [[ $d =~ (sas|sata)[0-9][0-9]?[0-9]?$ ]]; then - hdmodel=$(cat "$d/device/model") - hdmodel=$(printf "%s" "$hdmodel" | xargs) # trim leading and trailing white space - #echo "Model: '$hdmodel'" # debug - - fwrev=$(cat "$d/device/rev") - fwrev=$(printf "%s" "$fwrev" | xargs) # trim leading and trailing white space - #echo "Firmware: '$fwrev'" # debug - - if [[ $hdmodel ]] && [[ $fwrev ]]; then - hdlist+=("${hdmodel},${fwrev}") - fi + # Get drive model and firmware version + getdriveinfo "$d" fi ;; nvme*) if [[ $d =~ nvme[0-9][0-9]?n[0-9][0-9]?$ ]]; then if [[ $m2 != "no" ]]; then - nvmemodel=$(cat "$d/device/model") - nvmemodel=$(printf "%s" "$nvmemodel" | xargs) # trim leading and trailing white space - #echo "NVMe Model: '$nvmemodel'" # debug - - nvmefw=$(cat "$d/device/firmware_rev") - nvmefw=$(printf "%s" "$nvmefw" | xargs) # trim leading and trailing white space - #echo "NVMe Firmware: '$nvmefw'" # debug - - if [[ $nvmemodel ]] && [[ $nvmefw ]]; then - nvmelist+=("${nvmemodel},${nvmefw}") - fi + getm2info "$d" "nvme" + # Get M.2 card model if in M.2 card + getcardmodel "/dev/$d" fi fi ;; @@ -190,18 +300,9 @@ for d in /sys/block/*; do #if [[ $d =~ nvc[0-9][0-9]?p[0-9][0-9]?$ ]]; then if [[ $d =~ nvc[0-9][0-9]?$ ]]; then if [[ $m2 != "no" ]]; then - nvmemodel=$(cat "$d/device/model") - nvmemodel=$(printf "%s" "$nvmemodel" | xargs) # trim leading and trailing white space - #echo "M.2 SATA Model: '$nvmemodel'" # debug - - #nvmefw=$(cat "$d/device/firmware_rev") - nvmefw=$(cat "$d/device/rev") - nvmefw=$(printf "%s" "$nvmefw" | xargs) # trim leading and trailing white space - #echo "M.2 SATA Firmware: '$nvmefw'" # debug - - if [[ $nvmemodel ]] && [[ $nvmefw ]]; then - nvmelist+=("${nvmemodel},${nvmefw}") - fi + getm2info "$d" "nvc" + # Get M.2 card model if in M.2 card + getcardmodel "/dev/$d" fi fi ;; @@ -209,16 +310,25 @@ for d in /sys/block/*; do done +sortarray(){ + # Sort $1 array into new $2 array to remove duplicates + local -n inarray=$1 + outarray=() + if [[ ${#inarray[@]} -gt "0" ]]; then + while IFS= read -r -d '' x; do + outarray+=("$x") + done < <(printf "%s\0" "${inarray[@]}" | sort -uz) + fi +} + + # Sort hdlist array into new hdds array to remove duplicates -if [[ ${#hdlist[@]} -gt "0" ]]; then - while IFS= read -r -d '' x; do - hdds+=("$x") - done < <(printf "%s\0" "${hdlist[@]}" | sort -uz) -fi +sortarray "hdlist" +hdds=${outarray[*]} # Check hdds array isn't empty if [[ ${#hdds[@]} -eq "0" ]]; then - echo -e "\e[41mERROR\e[0m No drives found!" && exit 2 + echo -e "${Error}ERROR${Off} No drives found!" && exit 2 else echo "HDD/SSD models found: ${#hdds[@]}" num="0" @@ -231,11 +341,8 @@ fi # Sort nvmelist array into new nvmes array to remove duplicates -if [[ ${#nvmelist[@]} -gt "0" ]]; then - while IFS= read -r -d '' x; do - nvmes+=("$x") - done < <(printf "%s\0" "${nvmelist[@]}" | sort -uz) -fi +sortarray "nvmelist" +nvmes=${outarray[*]} # Check nvmes array isn't empty if [[ ${#nvmes[@]} -eq "0" ]]; then @@ -253,14 +360,40 @@ else fi +# M.2 card db files +# Sort m2carddblist array into new m2carddbs array to remove duplicates +sortarray "m2carddblist" +m2carddbs=${outarray[*]} + +# M.2 cards +# Sort m2cardlist array into new m2cards array to remove duplicates +sortarray "m2cardlist" +m2cards=${outarray[*]} + +# Check m2cards array isn't empty +if [[ ${#m2cards[@]} -gt "0" ]]; then + echo "M.2 card models found: ${#m2cards[@]}" + num="0" + while [[ $num -lt "${#m2cards[@]}" ]]; do + echo "${m2cards[num]}" + num=$((num +1)) + done + echo +fi + + #------------------------------------------------------------------------------ -# Check database and add our drives if needed +# Check databases and add our drives if needed db1="/var/lib/disk-compatibility/${model}_host${version}.db" db2="/var/lib/disk-compatibility/${model}_host${version}.db.new" +dbpath="/var/lib/disk-compatibility/" + +synoinfo="/etc.defaults/synoinfo.conf" -if [[ ! -f "$db1" ]]; then echo -e "\e[41mERROR\e[0m $db1 not found!" && exit 3; fi -#if [[ ! -f "$db2" ]]; then echo -e "\e[41mERROR\e[0m $db2 not found!" && exit 4; fi + +if [[ ! -f "$db1" ]]; then echo -e "${Error}ERROR 3${Off} $db1 not found!" && exit 3; fi +#if [[ ! -f "$db2" ]]; then echo -e "${Error}ERROR 4${Off} $db2 not found!" && exit 4; fi # new installs don't have a .db.new file @@ -272,30 +405,36 @@ elif grep -F '{"success":1,"list":[' "$db1" >/dev/null; then # DSM 6 drive db files start with {"success":1,"list":[ dbtype=6 else - echo -e "\e[41mERROR\e[0m Unknown database type $(basename -- "${db1}")!" + echo -e "${Error}ERROR${Off} Unknown database type $(basename -- "${db1}")!" exit 7 fi #echo "dbtype: $dbtype" # debug -# Backup database file if needed -if [[ ! -f "$db1.bak" ]]; then - if cp "$db1" "$db1.bak"; then - echo -e "Backed up database to $(basename -- "${db1}").bak\n" - else - echo -e "\e[41mERROR\e[0m Failed to backup $(basename -- "${db1}")!" - exit 5 +backupdb() { + # Backup database file if needed + if [[ ! -f "$1.bak" ]]; then + if cp "$1" "$1.bak"; then + echo -e "\nBacked up $(basename -- "${1}") database.\n" + else + echo -e "${Error}ERROR 5${Off} Failed to backup $(basename -- "${1}")!" + return 1 + fi fi -fi +} -# Shell Colors -Yellow='\e[0;33m' -Cyan='\e[0;36m' -Red='\e[0;31m' -Off=$'\e[0m' +# Backup host database file if needed +backupdb "$db1" || exit 5 -function updatedb() { +# Backup synoinfo.conf if needed +backupdb "$synoinfo" || exit 9 + + +#------------------------------------------------------------------------------ +# Edit db files + +updatedb() { hdmodel=$(printf "%s" "$1" | cut -d"," -f 1) fwrev=$(printf "%s" "$1" | cut -d"," -f 2) @@ -320,13 +459,16 @@ function updatedb() { #if sed -i "s/}}}/}},\"$hdmodel\":{$fwstrng$default/" "$2"; then # Don't need to add firmware version? if sed -i "s/}}}/}},\"$hdmodel\":{$default/" "$2"; then echo -e "Added ${Yellow}$hdmodel${Off} to ${Cyan}$(basename -- "$2")${Off}" + + # Count drives added to host db files if [[ $2 == "$db1" ]]; then db1Edits=$((db1Edits +1)) elif [[ $2 == "$db2" ]]; then db2Edits=$((db2Edits +1)) fi + else - echo -e "\n\e[41mERROR\e[0m Failed to update v7 $(basename -- "$2")${Off}" + echo -e "\n${Error}ERROR 6${Off} Failed to update v7 $(basename -- "$2")${Off}" exit 6 fi else @@ -346,13 +488,16 @@ function updatedb() { # {"success":1,"list":[{"model":"WD60EFRX-68MYMN1","firmware":"82.00A82","rec_intvl":[1]}, if sed -ir "s/$startstring/$startstring$string/" "$2"; then echo -e "Added ${Yellow}$hdmodel${Off} to ${Cyan}$(basename -- "$2")${Off}" + + # Count drives added to host db files if [[ $2 == "$db1" ]]; then db1Edits=$((db1Edits +1)) elif [[ $2 == "$db2" ]]; then db2Edits=$((db2Edits +1)) fi + else - echo -e "\n\e[41mERROR\e[0m Failed to update $(basename -- "$2")${Off}" + echo -e "\n${Error}ERROR 8${Off} Failed to update $(basename -- "$2")${Off}" exit 8 fi fi @@ -376,18 +521,36 @@ while [[ $num -lt "${#nvmes[@]}" ]]; do if [[ -f "$db2" ]]; then updatedb "${nvmes[$num]}" "$db2" fi + + #------------------------------------------------ + # M.2 adaptor cards + num2="0" + while [[ $num2 -lt "${#m2carddbs[@]}" ]]; do + if [[ -f "${dbpath}${m2carddbs[$num2]}" ]];then + backupdb "${dbpath}${m2carddbs[$num2]}" &&\ + updatedb "${nvmes[$num]}" "${dbpath}${m2carddbs[$num2]}" + else + echo -e "${Error}ERROR 10${Off} ${m2carddbs[$num2]} not found!" + fi + num2=$((num2 +1)) + done + #------------------------------------------------ + num=$((num +1)) done +#------------------------------------------------------------------------------ +# Edit /etc.defaults/synoinfo.conf + # Optionally disable "support_disk_compatibility" sdc=support_disk_compatibility -setting="$(get_key_value /etc.defaults/synoinfo.conf $sdc)" +setting="$(get_key_value $synoinfo $sdc)" if [[ $force == "yes" ]]; then if [[ $setting == "yes" ]]; then # Disable support_disk_compatibility - sed -i "s/${sdc}=\"yes\"/${sdc}=\"no\"/" "/etc.defaults/synoinfo.conf" - setting="$(get_key_value /etc.defaults/synoinfo.conf $sdc)" + sed -i "s/${sdc}=\"yes\"/${sdc}=\"no\"/" "$synoinfo" + setting="$(get_key_value "$synoinfo" $sdc)" if [[ $setting == "no" ]]; then echo -e "\nDisabled support disk compatibility." fi @@ -395,8 +558,8 @@ if [[ $force == "yes" ]]; then else if [[ $setting == "no" ]]; then # Enable support_disk_compatibility - sed -i "s/${sdc}=\"no\"/${sdc}=\"yes\"/" "/etc.defaults/synoinfo.conf" - setting="$(get_key_value /etc.defaults/synoinfo.conf $sdc)" + sed -i "s/${sdc}=\"no\"/${sdc}=\"yes\"/" "$synoinfo" + setting="$(get_key_value "$synoinfo" $sdc)" if [[ $setting == "yes" ]]; then echo -e "\nRe-enabled support disk compatibility." fi @@ -404,43 +567,78 @@ else fi -# Edit synoinfo.conf to prevent DB updates -#if [[ $nodbupdate == "yes" ]]; then # For future use - file=/etc.defaults/synoinfo.conf - if [[ -f $file ]]; then - # Backup synoinfo.conf if needed - if [[ ! -f "$file.bak" ]]; then - if cp "$file" "$file.bak"; then - echo "Backed up synoinfo.conf to $(basename -- "${file}").bak" - else - echo -e "\e[41mERROR\e[0m Failed to backup $(basename -- "${file}")!" - exit 6 - fi - fi +# Check m2 volume support enabled +smp=support_m2_pool +setting="$(get_key_value $synoinfo ${smp})" +enabled="" +if [[ ! $setting ]]; then + # Add support_m2_pool"yes" + echo 'support_m2_pool="yes"' >> "$synoinfo" + enabled="yes" +elif [[ $setting == "no" ]]; then + # Change support_m2_pool"no" to "yes" + sed -i "s/${smp}=\"no\"/${smp}=\"yes\"/" "$synoinfo" + enabled="yes" +elif [[ $setting == "yes" ]]; then + echo -e "\nM.2 volume support already enabled." +fi - url=$(get_key_value "$file" drive_db_test_url) # returns a linefeed if key doesn't exist - if [[ ! $url ]]; then - # Add drive_db_test_url=127.0.0.1 - echo "drive_db_test_url=127.0.0.1" >> "$file" - disabled="yes" - elif [[ $url != "127.0.0.1" ]]; then - # Edit drive_db_test_url= - sed -i "s/drive_db_test_url=$url/drive_db_test_url=127.0.0.1/" "$file" - disabled="yes" - fi +# Check if we enabled m2 volume support +setting="$(get_key_value $synoinfo ${smp})" +if [[ $enabled == "yes" ]]; then + if [[ $setting == "yes" ]]; then + echo -e "\nEnabled M.2 volume support." + else + echo -e "${Error}ERROR${Off} Failed to enable m2 volume support!" + fi +fi - url=$(get_key_value "$file" drive_db_test_url) - if [[ $disabled == "yes" ]]; then - if [[ $url == "127.0.0.1" ]]; then - echo "Disabled drive db auto updates." - else - echo -e "\e[41mERROR\e[0m Failed to disable drive db auto updates!" - fi + +# Edit synoinfo.conf to prevent drive db updates +dtu=drive_db_test_url +url="$(get_key_value $synoinfo ${dtu})" +disabled="" +if [[ $nodbupdate == "yes" ]]; then + if [[ ! $url ]]; then + # Add drive_db_test_url="127.0.0.1" + echo 'drive_db_test_url="127.0.0.1"' >> "$synoinfo" + disabled="yes" + elif [[ $url != "127.0.0.1" ]]; then + # Edit drive_db_test_url= + sed -i "s/drive_db_test_url=.*/drive_db_test_url=\"127.0.0.1\"/" "$synoinfo" >/dev/null + disabled="yes" + fi + + # Check if we disabled drive db auto updates + url="$(get_key_value $synoinfo drive_db_test_url)" + if [[ $disabled == "yes" ]]; then + if [[ $url == "127.0.0.1" ]]; then + echo -e "\nDisabled drive db auto updates." + else + echo -e "${Error}ERROR${Off} Failed to disable drive db auto updates!" + fi + fi +else + # Re-enable drive db updates + if [[ $url == "127.0.0.1" ]]; then + # Edit drive_db_test_url= + sed -z "s/drive_db_test_url=\"127\.0\.0\.1\"\n//" "$synoinfo" >/dev/null + #sed -i "s/drive_db_test_url=\"127\.0\.0\.1\"//" "$synoinfo" # works but leaves line feed + + # Check if we re-enabled drive db auto updates + url="$(get_key_value $synoinfo drive_db_test_url)" + if [[ $url != "127.0.0.1" ]]; then + echo -e "\nRe-enabled drive db auto updates." fi + else + echo -e "\nDrive db auto updates already enabled." fi -#fi +fi +#------------------------------------------------------------------------------ +# Finished + # Show the changes if [[ ${showedits,,} == "yes" ]]; then if [[ $dbtype -gt "6" ]];then From 0e4c229feed31abafa9133f4dd6efc1f2dbb1710 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:01:07 +1100 Subject: [PATCH 16/24] Update syno_hdd_db.sh - Added support for M.2 drives on a PCI card, M2Dxx and E10G18-T1 etc. - Improved flags/options checking and added usage help. - Can now download the latest script version for you (if you have user home service enabled in DSM). - Now adds 'support_m2_pool="yes"' line for models that don't have support_m2_pool in synoinfo.conf to (hopefully) prevent losing your SSH created M2 volume when running this script on models that DSM 7.2 Beta does not list as supported for creating M2 volumes. - Changed Synology model detection to be more reliable (for models that came in different variations). - Changed checking drive_db_test_url setting to be more durable. --- syno_hdd_db.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index fbd0d78..7f89b5d 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -40,6 +40,8 @@ # Can now download the latest script version for you (if you have user home service enabled in DSM). # # Now adds 'support_m2_pool="yes"' line for models that don't have support_m2_pool in synoinfo.conf +# to (hopefully) prevent losing your SSH created M2 volume when running this script on models +# that DSM 7.2 Beta does not list as supported for creating M2 volumes. # # Changed Synology model detection to be more reliable (for models that came in different variations). # From e89f1da2844fe17bd1b6db55e13a47f28a5c64bb Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:03:33 +1100 Subject: [PATCH 17/24] Update CHANGES.txt --- CHANGES.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index e784b34..10b1012 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,21 @@ +v1.1.15 +- Added support for M.2 drives on a PCI card, M2Dxx and E10G18-T1 etc. +- Improved flags/options checking and added usage help. +- Can now download the latest script version for you (if you have user home service enabled in DSM). +- Now adds 'support_m2_pool="yes"' line for models that don't have support_m2_pool in synoinfo.conf + - To (hopefully) prevent losing your SSH created M2 volume when running this script on models that DSM 7.2 Beta does not list as supported for creating M2 volumes. +- Changed Synology model detection to be more reliable (for models that came in different variations). +- Changed checking drive_db_test_url setting to be more durable. + +v1.1.14 +- Minor bug fix. + +v1.1.13 +- Fixed bug in v1.1.12 "check that M.2 volume support is enabled" + +v1.1.12 +- Added check that M.2 volume support is enabled. + v1.1.11 - Added support for M.2 SATA drives. - Can now skip processing M.2 drives by running script with the -m2 flag. From d9fce321b0bb2b885fc759e1b0150206542385eb Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:06:46 +1100 Subject: [PATCH 18/24] Update CHANGES.txt v1.1.15 --- CHANGES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 10b1012..20b5d3d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,5 @@ v1.1.15 -- Added support for M.2 drives on a PCI card, M2Dxx and E10G18-T1 etc. +- Added support for M.2 drives on a PCI card (M2Dxx and E10G18-T1 and future models). - Improved flags/options checking and added usage help. - Can now download the latest script version for you (if you have user home service enabled in DSM). - Now adds 'support_m2_pool="yes"' line for models that don't have support_m2_pool in synoinfo.conf From 6b6c982765a598f5c9d4c0e7653d38f7a00314ad Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 17 Mar 2023 18:48:00 +1100 Subject: [PATCH 19/24] Update syno_hdd_db.sh --- syno_hdd_db.sh | 64 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/syno_hdd_db.sh b/syno_hdd_db.sh index 7f89b5d..a17b6b2 100644 --- a/syno_hdd_db.sh +++ b/syno_hdd_db.sh @@ -33,7 +33,7 @@ # It's also parsed and checked and probably in some cases it could be more critical to patch that one instead. # DONE -# Added support for M.2 drives on a PCI card, M2Dxx and E10G18-T1 etc. +# Added support for M.2 drives on a PCI card (M2Dxx and E10G18-T1 and future models). # # Improved flags/options checking and added usage help. # @@ -97,20 +97,38 @@ Off='\e[0m' usage(){ - echo -e "\nUsage: $(basename $0) [options]\n" - echo "Options:" - echo " -s, --showedits Show the edits made to host db file(s)" - echo " -n, --noupdate Prevent DSM updating the compatible drive databases" - echo " -m, --m2 Don't process M.2 drives" - echo " -f, --force Force DSM to not check drive compatibility" - echo " -r, --ram Disable memory compatibility checking" - echo -e " -h, --help Show this help message\n" - exit + cat < Date: Fri, 17 Mar 2023 18:51:51 +1100 Subject: [PATCH 20/24] Delete LICENSE --- LICENSE | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 9c3fcdd..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 007revad - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. From 6f3b86663ad9cdb39530074fd633b00f3353f654 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:00:55 +1100 Subject: [PATCH 21/24] Delete images directory --- images/schedule1.png | Bin 60535 -> 0 bytes images/schedule2.png | Bin 12936 -> 0 bytes images/schedule3.png | Bin 18749 -> 0 bytes images/syno_hdd_db.png | Bin 23731 -> 0 bytes images/syno_hdd_db2.png | Bin 10601 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 images/schedule1.png delete mode 100644 images/schedule2.png delete mode 100644 images/schedule3.png delete mode 100644 images/syno_hdd_db.png delete mode 100644 images/syno_hdd_db2.png diff --git a/images/schedule1.png b/images/schedule1.png deleted file mode 100644 index e133044cf4ab0d44bca055e3f7ca74ad90e4c825..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60535 zcmb5Vby$?q*Dj1miXbI}(%lRx-7O^{NRG5LNDBiQrbeDA3pmcY4$Ivj;P-oEJ zdCz;^@4CM4`u+f}XAgVt_3T-D@B3c&TH$Zh6mXxse1d|4f~%w`tBHbw3Pb)hVWA>h zUX9|Cp`h%EE6GY}d(Q5qVEPkp++L*3G@~krEkB{AkbRRG&QKE;kZ;vasQh*MQRMp! zQrt{h+D!R~CswqfM*X&5aKBLpWR}a`zkE76_lQ<^`Cxf@x%U7%w&j((Z@2X0*4H#@ zVdjTbs#mUP+LhQ4ZySN104;vQ+WCn3P?8kV1{9Q0vZy}s2oFGN${cimB+H=i^zlP8 zK87)<0YWAHCwHM>@aaQ~q$fQX`#3Ef`0(I_o($Y#&e+Eq0X#g`p$(?d!NJ%keD}$) z{)ZNnAWX!=OQIzHah_RFWTq!oIZf5J!gy$+79~%dczc7N105F#isEx7w>lY%3EmZf zv-A`Ctx22SFUM4|dQHf}T#2ZyHm~n=M!6^C9zFE*_`R!Ke))MSF@iZ^sS?yjjY8wplkUwGf&*Bo^=lhy!6hi)5f8f7XkyEC?JWU)4wY%R5 zTRIf57Zctrpt?1JU^xOaEBJ0subP$?`dJP>Zl`R`8GfuhioHmDzx-QlLCc8vVQMGL zIH+QDF+?6zb0E4$#C_*FKVJ=9m2SPdTK8%!0NuDY79DE0ah*AeE*$iV1grm%WG0@L zs8;wd6X@;+TP4Ifg~2nLzG0QaiECD+r_Y}gq=7UO5PqTycTZG7cui-njeQ5iP_#gL z;{2pdJn&3~XX}?CEFs%g<*ZLk-V4>B{_iKz9N8DRm5fjO)ZPAm`vrk?dPYHbEacd) z_9IQNROevD@Qp;jnPng`S#;QY7R*Jj+*<|@#kAm3EC-^>;c# zYoA+;XCxw29Iv}@)qSK8hC&yMyuxyI`QM=9KCc{CS3iDweXsFM%t^;ER7(o0vw8`)g~7SEp(t^%Mz-FFvhJ4bUO*>BwrrxE!9O=;(pGe+KuqlvQ$ z-ZQ0&$B*CY^@0#mT;H$GWgB$eVo6?M!qxr-Ji&K$Q4-pBmai8_=RE4VwpU<1WbJNa`lur?wr?QT7 zXNuDAHC%W#Ud%emhLXB%40f!R#+51_WYVhaL4#7YCSQ6v6WBKo!h?UP-u+6KxA^K+ z(qu9vVLUtdEBJc}#b2Kf3j>2Z!893f(qBbv+}HZ16$0;luABRSjqh%E;9WJA9%vymRnSXG z{nP2XN_=lUa)+6U>HxH)Kn1+L`}1$- zOrTxclp)|ik=DRiO)>lAfY{{X8><2e5=3V8SsCweQCRkIH-4o?S$|wUOUkd=jFXIq zQ^6laq0UD-b1L!hPS+#{xFxEeI-xY0NJlYud4luAwy+3>hatq7bn&g>UUX_@DocnH zav4-UcK!N#rnplWk$H*@V++>@nFB_4AeYsh)>B4rdDg=q#Nn|OCZ)h2Hwx@+9ON|V zwDKU?%-!pgeLp`EV}t#zlT(o@n{VFhie~ovcW=VhUfgX*{kmzzF9m+yT#o(uxCmr> z50SY1DB`47e-lu>bjN?cZqUJpN@EO4tvn30ow;D($O01EL86JkJL~K$$T_IZG~mH> z83`ZY8@q?TPtXEVL_F-4pv8PS(7R(0USI74=*9kK{*6V#(#m$-{Bb0qb ziOa|6=631C&ka&0$t)T0xq0YW87S6dU1OoQEAgT!ai4+~f^{qOg^er4r~0#W6^GIa zQKtm$Fo2Q8N{{D5Z$ihZdx8q7{NIE2VM*1b*J6hNHsO}b@WiD(yAL0>=UQr)(il{+ zF#_jm>>TH6jC$xKEZo@f8xA7&u2&pWq7qv#uwu zjRwfr?caTYQoh?)2(01f$C0RO3g>oE9*^v{6)gvf&%`$H#0NS($b>F4>NUcSxSqK zk55XnMa=%aJW=S%VGsKUMKbO)^x^Ms3(3D{@-mMpg&^)jON{w{uJ;$i|L*mte|H>; zVMs1eF|T5Rs7wxg@fhi~x<8IjPSv3kiElZ${%>YB5cPKxFTO+9a}E4}sS)#+wr zV`;r?Ho~=zL>`S9?p4T2@%pDPxanud`ds6?j?+E#$1=r)NKdoa(~t? zt{PmsmEAb!BXQutdCV=vJ8;#;!fTJiy;GWlRSVQV!;=f%(FYp%Bbpl9%7u7`e1AL> za=iX^m-@BKzl`s(+ZU4ZwhPX#qLd)X6K<*?1ETG4{1%|+sgg)GDx>xZpu>@qVky9 zua%opXK)9zES2x>UnJhv`I>=m|G4kZQhN7~Bt|x+tCvz9vn$7Nt>yv+7P7-}R8?_z zrnw&j)A>q@H2y8zaN_rsuuNb^`*znXRl%U*EIt)jL+mVs ztQ!Z2MFoQ?GFgb8KaXk6?-&-kNF$rs?z{w`hG9jSvmr)_t-yMxYqKri znukXThgFAqPnLu?b7{ILc0~*F&vJaaN+iTCKQNQ}eCW+y!+4hMr{8EYR;93YM3w4! z357O$hxAF04VFR;Jru7O-IsT)&bytV*s&(Ov_S&Iizt@A9`@%&w;L2{y|5(^KA5-|ggeV`Z~n8hH0`zxx>{{~zNf z%cbfEi$7Bav_U}@7q0w+$>UFxHeL<37YrsuHI!k_Ek;u{SWP&le&=q2z!wYwmS|3JX&LuO$j4fpzH?Fla!0aXL_QcVQY2D zKCJ6%Z34U4>3BTTk~3r#KY1i8dvlgkU%&CK!|#4`?yz;xtG9>ASO5mw+xu1KB3}&5a=h14wO@#j zo?j|e2dC^vtsC#S#5F2c#vFa)#N9f*T7dcpQ8@!;BuEo zl_v(*kF1i{$4ys%njqM&wf1wP@0Hca-CdzoG~N+W){S0)UsoJr`F%TNKtYcSZZ3vE zC%iyzU9Jpb81+gq;%CZ5|GR=4ddiOzD)8VZ!nDCH68Wt+ zaEz+ButcYYgoH%&W*Hny@-Y)Gmw)$+(q*hVATvQ*gF`DZG zQh3dlsw=HR$E4T0o!8DU($A@%`_L^oDZielXt0R0J-Dxp+LVT zu<5kdov>d?+c+UHcm`@Vm3>X=jt`~@fdUJAj|$5RieFL?sB8?sZ{EP_I}m-n$3`ay z8h;UV<#92NsXP5X+9CD}Jq<$onQVmXa+N;h`;8@5|F-33smFb3C{!n%Ge8);VjDZ< zU0Bc~u+(rpxFB)pbzZ-9aj?+mcQBgMXJ0!%-)u0Yh$AG0BxkBKqiS#C;iCZ7wgq}A z4Zn(TDD!bfSS3XxRPYV{^Ia&gp~3LFR|ke*1?3hNA_i)g=E|Irz>4UQvu%j-)8>o3 zYFn}y&r#0{u!eRg%n+gos;X3HlPMoi!}ZvKTUfc8ux=}Vp|@ElC+^YJ-ygL!tAsw2%epkw7PuUFtB<*sNY zi5Q)vL)Rx>FM$px=7+UFhn*9te5qwZV!}AnS2BSrMy;L6a@j@2R}9mhk8&EB2_eQ2 zH$7*gY^A4E4s{1FcU&P~+hswnV`Ivo^=~{GfVfUXt8RnixlWWYOi-y1dPFWXdb!e) zpsTHu>V+u9#1&=~F}xIgB=?8fZua#tyj*z7bP`ar#;aAcI=kUYXEPTJZCB)h2Tu|g z?VQUN1Cb}m;^}hMO=#$0lIZ34M{xCB0ei1y0-EhryLAFcAw~PR1pQXN7UCB*f{@L5 z62R+06B}A;e+}J+cf7+bD^^SxNnCgP-ERnvH3*(%ee~UR0ubMzXOpE;18rAJ##Af1 zE1#kr3Lgh>0HoWr)VCNgz~Qm7Vr~Me@Zhb(d!NJm=IZvt3y}NBmDLR*+rbFpyQp>5 z;Rp4;zV$;#{mjN$fAmb(h{WbZ3doFv7}Mg?1kn*dOhgT$sx`eE6D=WX9u3yLp{&^oW zmFNep{hIiEt+d&jlK<>Lq`?($4P$(nnxOEo_)hnVsjyTf$w91Vh+pByF3wz0$V)FY za7I`X@{W;~xRs+X^!+*;hS8wZ4cB>R|2Qrulv15#1F%iP=k8kjfmJo0N#f4aCR4 zpvy{@E_xIMnm&K&P84=kFV8_+dzioVb*7tcY&x%I)Ys}6Q`*5Lu0c0yY~(}$v>mGy z7<|&5CFwR@Z!~owXR&)u;Rw8%n#E0mJ)>N;u#jw71SEcWcR9M7RO6@AGjRWsP3D51Afv5I!RbD5@ z3go#7=>lqp3%V}%bm}@fZ!dPoc6$^KqJ=49KCIr1qG)A$!AkO+j3OU!y9Yonc~x^b zkyPm`v^^1R2ZsQ6v%Eeh7(L~%ez)eU-AgBFa(FOa^LJFRv%%jU021`ukeEx+;b+Ku zq5|q9&IvX0SW{kwqt^upZsRQMb`Wnv=4^<~r<>E6vEU4r>A>IU^hY_5h+iN#t@FQW ziP4e9e`!3k7%PGKE;L?(4PSpmkCUM$oo(TKnyi4$}ip; z3i?Z0g0KT!^BC|2U9;;O4&H0{HoAM&6L63fK#wXOn9E9MZVXlr7ufng)a43QD6{DY zaDi*!=yM38cv~{65>vRd5q1_cp&?enKRQEew3?)^ALnkeb>V#7WSC@&@5sfE`O>rC ziKV7RJk6ybr+`S2)^(HOLa=N;Fs|aLrkzTy=?@yJ)LT>0=>J2%Iul#}w5hiCJXgue zEbHM)Q(p8)(nrm#brSd0=`b7RZQIdnWscB(jv5x$jbxd%%Z4C&Eo409v!s8E|G}1p zAj%7OHlN6t{R_A5zKtSGB$sByc#IMz@<17BM-%-O!7^s{GDNeqM*oMl-83a5SHPD5 zNmdshBl&B%3^-OA*wk26Rdr+NQpVK+CdPeBy|AoWRd_C0t7czWQ9%#>{0C*38|e#4 zf>Vj_xw;#bU0hBNeug|!a67)j_iz^b{Qg6q`ox0BhJ}^YDFz)sO^&b@ioa*;u5xT9 zaAipl*WbXY1gN>4Q&6z8)j;R@B-3iTtg_IcOGijZ$OeURLI@S5oyZvUL>5f*XY=S# z6!kX;GF~_^Fwg|un_0pFA3tq^y6(sH?JB#wze29XAu?cZ)c!2v{n+AP;=b|*l>JB{ z4ysN5Apq)$lm#N@w(=1HucS~!kwI4^sa6g_vije1l7IQUxnL8Ne7Z$Kgh_-A2Z8F3 z`H$T9IN^hxr7iZQngoX*n{WCC{iXapPU%3k?tU9&C~ebsT~P;6t}Kom^2y&Jouw^x zycg+sFX$9*QiP~5!H*~(BjQ#hLCG;cCQ>iD`){%S1{40jnwUKnHUtSjv}<{M_V9_Mv%x<{JiN6sFc{T#J85R;}KD0w!SOfhX6}KPl zL4gry^nu#DkZn$IUNO1fFVT#XtYh^UO!j9_b+;j%Fmzp2+VM#_O?I^k=NYO__uj+H z_O=VRgRfMo;mCzqNuOP_Ed}=ApU7-1J58kGHoWA1GFnThikZBv++l^I8~4Xt)lJaj z3)qSwJgA9pIn`>BKrR?3yrDImO66V?r|0y3BdYJ|j^4s4fhJ)G`Z%RbF%ixA^KhpT z5G(kpUmGj^+lC)M)7e{fgR=T2;~x=`3^dh+z1AyG%dXx&IGYJ4K*umtDm?3uIs;N+ zkNOgCQ3+Tov$R-Egm?bfX$uhpVnh){3tKjik92o1jO2*KpYJcHl*g%{Q_RJb$PljZd}iRmc3$lTPEA<0NztiS0zHb{j5- zaXAe0`1-iw-L$#@1bVd7Qm^(}`^nK!_1>=S*Xq6uRFh+ix4rE&i7KKHu2(V)A4Pd% zlO>uy%|zI+vOHo*mCe~iD5uHbZd|<2I|P)ln@|6mJnM*IwT^-`8B@4iZ|KeLe0bsd8B4o!wlMniHsqZEoP?LkIIf*d zBunt-tNI`z8%9RWJ2?yoWA)B_HXay6GcBC?`O_>Q_y;W1v+uoTF))t$r*dIgU=546 z)j(^#`CdDXscPvS&nFDXP(NjMlrScO_Tb>Ia@Ug(ucxRYCmo465NF((bxa195U>Y}`*us%F z61!p%q{Ysk7T&$io1CoBbC-Hpia*vM{g&>5tWxTSK-qt7W(-S^ez zgKyXLZzdfCyh?~vh$V3gPzr<2U#*h`(e0n;gFa5i4Cy+~l;<(h<3vpR(EDMB8#%NO z^)lVHjd_49604*@+t+gYHR?a@HA;hRQWn;XOnTXQtb0E?`WzN68o8yHt#)$?db^M}UUuat*czb0G=A3^;+$1(7|sh`6N8ya zvT6|E{KZ&Hl^vu2y3MMs9%F;#NB95=Q3E%q`1)^HfP3=k7~n$7iX>ryJ0Y#a7oSNX z8`xl`F8V5H2ZkAcLt17hI$AS0KC)paDw$g0xE}ze59OLjg+^!=i4`3X;N{v{hd5@Z zC--QA-j!xTE6(^tjEc*|qy@nlke{4NV@B_hQpjqi8W;9RqH}Z$XEoXx>w)X_H!F$j zNvk=J!+29}(-=9}Imd68 z^NX|cWI(R;_Uo}EYDiW!?f!zGygH{BCX2+1zq}w=Owy0$*cf=gCS%&Of!qDhvIFEZ zME|J7dF^5c>sH6jPZfm02wYj#}k_ z*FDwYdCut>6KyIHs0h>L1O-sMM6k5N1#81b1@ECRj6*>=M0!ZIdC~zx9yCp+g^07U zGaFSczp)_%YsgU7cqE?`mw^=xqn_is!i0MPHMr76_f^83`9QWVqMa#QcO{Rxpi!U> zsNF5{%RTdqcANtubDy8E0Q&vM!Ov-U$2wO@gg%J$qB?>1c$)6yv&UrOc_?|q0VC#| zP4vDqEq8m>ECd9Xb4@grV<992XW)zcA^yO@Qo_&_QZkG?5c~2n9f;xJdudUil%Ma? z$Rd#NwfVXu+Q4HsDPsN2Q-$$C;3|BJs&0|f8c}Hf(X0?nJ1zs*ko)K=YD{S@_7j~k zc`mk6EeRr5r-Wv_1Ov$tqn`81VA#_a?%I`aH|%nI(6CGa+63u}4%l6n0F|9|M(@8Y zIUk-UbMUhkc*h?I$WT?0jO_^K)Ri1Ja>kNly0JS)b_J!9v0r&-f^_LeQdNCAvN*h_EK>8{;tBa1q*SyMT6wyfs zxpdDw3r@T5Fy5<6?S=<)T@-Zg8(uGlq5~?YTy;{J9f^2{l7^*jh3n6FA^JmRNLmlYG+-kW$S)W6pxKXDB3( z2J8AHP$;Y)E4JP^_BV8JTE{nP!s-cLlZw7TWOg*?i0qU_Dm27anXa1uMnvXfv^~vw z`!OH>d^j}atASU1YBz!}11OvhG)70PqHRM2y5AwSGBSHla6yEaQ25gAj^6QSAl$`m zgBk)SCEd~830&nnxp9;b8sxN|`#h#kDtZhC<)7hwr~YDs2LKar?R1+`NKA?Simu=@ zEBfJV_#BRoh?_xz3l#7%#)~3gM+8*6Gc~!rJA4R#KfHmaRn$n=+m#|uA9ADmzGwbJ z>M@Ex-v13g&7|Qu>w|e;2kT6=V&ScHIW$V(cz+mB*4~WPe23Q~r$NOZ@IPQ>FQWBY zCcS{xI9$!>Xi~toFK38G^^JLShQt`I(oIW?c*!B%8mH<5hC~7XUl>>=42lx-F&+5h z@$KZNGhTQHc51=-w!rR48ZX+=URRj^KiG^$uZPWo6i0$Qb7$kf25V8jVB}7ni6;1S z<Id7tL?k%JKcv?!xqaopT z{3T48OBRnWzQaneoZ=%ww1~vy6oQ|Bv?m{{@CAor{<9ouQv{OnVjIfdZB3_ z^WPfi;#7sq)JUPV=0<3xP)uz+^ z-SHS8W7gQ3=hiTVHoF?C4NP<2$}H~uaUGp1VkY}}?PHi4i1O3&-H4gv&PZk6PAT3Q z`ZF>(S8=7HudNF(Tn)r3o-AzBG2Br(#1^H6x0afo^sdrr8q&OK_5wapNrb#Cfu&8-cSo2jZMLPcyCrM)xQ5>Lw`1x|w1_y)08{nv+sbDVm_o)1#fF=Vqnl>B4aZ=dstP|U=JLsc>@6$W7XIG4nKjhp zr^-7;IJ=vbagY$b^AsyNFW`vEMz0sY~i`=iG;>-#99w;)Q@45!HWapRIRqlZy z3BT=8<@hWho7)}DJ?rE_^SV%x1k`V}Fe46%b-MRPJLF0H@L0hR;%yk@YhRocxaRfb z)4pv;LfG(V6^vca;__-~|5c#6>R6&;)|)u!(bKDrV?S~MwF@>lI=%t;g~&Nc+TnI1 z$zW4e(l4NNb+a}i1yABviZ@b!g2g>n-F3U0yg&CM+W^v8u}Gn_7IJ@>zd;8O`qo&q z<)yTkHgLK0RCRz!ifm}DdxM}Br`e)kRfuM#zSnj8V?*F0!I!^bIH%vP3SRe1w9o`= zmd7}o)qG7Tp4w7nkA#l7?hEqi%S1187Y$k^KG&7nrv0WYGcd%?qr^;NpK}8>m{#ch z{t}f80TVm_hz;DAq;v%!-cAV5-KfI#4AO*T@V6gpj@nfbjD8GH; zwb&IH)Gnz(a~AIg4-V%g$P=@?)C32JraKT+vuE+-Zdf+Z`mS2#u_<#0KYcjW)Ig|@ z;!;%A!!Ek%B4uGX{6=laU@$6^PR~zAv=pqdZVPDoq%4EEW!JWq1CzR{p)4&AX~FJ6 z+QF?$7iq(RG^j~x@^eEgrO|jP!LIUI*UjziCrc7;dCd;(gh@sz0WPJB+j1BL@r|Az zVTzSZFA2&Ip)7t^v)Ij4oe-<2RluVc+fb)OBZFK;XZX004fEL@QjjD6;wQJQ4GJ?H zvyG6o@ST!0BWJ}A{HI8drEk=1B%6a!Td`o5FjRIjfH_2T#h zMlDIqc$-rs^cguH=VbsFCGB6ug}nxCQ<6ThC5J&G^lt%m9EePZ+(`$EOBPN?;RZMoDD=QQbx^LWXjY&`LypkrO!>y^TF^PxP1S*l@FfZ zy~0*KRawp#CI=5rbHS)r2K0@xrQjWEpkI_1v?almM{>BEF9l8M^`IT12veVV9Ns4?l!6?hZnf5qsIT$- z$KPiHSLuwA30~n#K(LA{oPqUM$)SdX_@J$MI+VWCFuu}lr1UGL{W!mb?(Lo;Xmls% z(TiiWMRU=E;7BMkuF1r0Evi{+DljkE+lv;Mfq;%DCLS^tYvu!8m1B55D)>{5WL4o? z2(yd=EW5u=KCwK}mSjo69MV5S27Nn>&Cc0Vs3#0R_#CAlDgGAe@nJyFS`Vl;lQdIP zh{7Ab>`a#?cCOO|H4w&Ji(+$UV0NpRY~BfoiP?0e*f@vF34DS_$!St%k67)M@z1U4 z*}p2Btri%rp@1_CaPz_2BlOsj$<{pnVT)d0>yR*BHii&9;-($f$eJYa{7qrDeJF(2 zsE|b|Gc8>PY?%qve$Z>%>=G@+4T=+4FvddhVX42~owuxYJuM~Su&T2@i*hG z_6j3_hMD}kUJXMoB$nAk1mqo{Mw=|U>3a1Ls6IhPpEKz!5EU}_4X+`2sIW0^apF*; z7>dld;;$o>@+)U{Ad~so#Z#;lMQ0Tq@6Yk2`=n0bvdvI@#_VjWXiJ$bXMrs!V-@VK z3FNt(J9maokNR+3C(uRzg-j=O9*%W1d?wO;%YOz;<*>lcI4m}znF_i}kL%b|pLlX& zPbn+a((1(Nl$}PDM=G9m(59dkoxx76e6UQuATq(YrNH9J(j8YAFnro>eAHMFk^%gU z^#A}vALr#naQ%WVFLYQ37Xmp3R5RY6G#(TVFr$NzisAeDmh4gUU{LlzeInTBd%L_43O& zCv~suzH`r}I(iiqoxDWXP{sX|5#brxLZJK3_mV^ow8~I?{j-NnX{QvzLcWdT^neHd zJ0yS9{(cn2w>0+sZ-9+;2fyw_SA9?Pi|<*u4duxW=h~7AGV>GXDZW_>7y4CU-y=me zL4fDw(0AEpwZ^!}ua+==v(jkm3Y%dXgg*03^Ot`HL@y z0mzg-=f`1C|Mve4iPM4pk{}++f4O=O34dsaxZ?+Lz&Rh7@kX%->q6jMqVV_Onr4az zKE^f<^>E^s(5XaeIS|(gmS<=fJSQh7xD=}hkDO(1911or(%zy7di0D8?Z!yn*q3CBR;c(e zApp@WW-=c>VpC@!WFlw3pPE`%*~TgRT@THFL<$ua^{m@@qb2F{isEO?DB!A~u~j+x z=bXp3e<-dcv2WD6rSravP?4oEk_S-l;`rgbv{_6X=HFk?t%NOsFaxA*`TQhP+&W9? zxJZ>my8TZTQr_6{rg;3kfEIsk>FuOzW9y4)@O#3mrG*x55+EEw$x`DA>){9a8L$i) zzM&b?bL#A{x(L0?7Qj0TX5LpIhe`Ic!QCM( zc`t{|1|G~bE=)yH@(35sAoB*!K#Em8PVd0q)aZjaEWLsZS~J~8tknTquA(He2gOgv zIa5T0^o`F6V?WC{3Tia#_ngpJcm1(XyF1;raSnL}cf|$66uzXX{>rI)ZG>L( z-C9)^LCa5b%%6!6_;Ju$nN?AvtKn-7(H=i%jj|&clHBbxDdC5s49+`4om-d{(rmpyJ5k*TLiDSrJs`# zW+R0lAZij zaKD$|9yWLOO4Ga`ZPO`p`?YcaJjdbw^YbF;GEl%O_0z{G(|y*;yiDX*>(@v1t}Qfm zq+AA#+ewL0wq2fd6&EW3%`hMuKNgBV@;(e11m4QtNN8CO zDGme~FI;wAz^NQ-Htwtv|%m2_4t7qpLW1^{Oi1VHOj6wl-WbP}pY z6BBg=7EemHIfdp=l7y4rB!BBfR5)FN&Cdz12z8EEZv8xK5)l*JZx0v1T?%cfKm1Hc z!3Dz8ak(2PnzBE)l^cG2eTxhSm;9`-Ga5PZ@;ar+gHf^l zZtR=(Sg-5r%5229dXzMt-Wc@Om(LeocnUyjJc=H4g6{+PG-T@vIdk%K|F<%Sen_c5s}c6Kek1*@$A5mb8ER2 z#e3IFll^%}E>HtN`9Z%FCv;U*XkA@?@RM04@#}27O{ulZ$KS#f_Nq>GRRETpKWgfR zOsiie6s}`~`!}*DUU6Y7KvW>R4Wa zz1F++&B3x)s}AdH0iAUfk9jZ17~-Y(Blamc{Bc79ba#}1z{ttS}Gs@?XC8-;np^?9cIlZ8 zm#KoVxCqq9k0Ep0(w6G4OIqhP)5i07DPLjH!^mFx70xU*gNx3FmRt{`xJ!rX)7iT8 z$n8{A?cBzI{pw#|x(>7=gTDlzZUh ztKq;#SyclI?aa*Hzs0yLE&TJY9!JRotT(8_-R!3cOmX#;mw{G^Nv4{X97aHIq&=t8 z(}8n9-;0qkJ#!Ud%kK5y5gWTAj`zGu3vfk&F4%atT zJ1ti>vs-y$*TXXnt=)pBy zAbRlSVuu5PQEx)QOg6s6)1sJO1rSfGU8BPaThpFwNinTpw-A#dQ74m(_>Ww2-TO5ovzzSuz(WytiIW|_X*0$&yh^uL(e=d( z#~1z1WUos<%?qqmH~Ov+VUQOa@!g244FlpA$&h-^0F|e!(IEUh{f(6lo_^+e1OLwT zsv>Cnj{KOkkO(8b1l~J~y8y$C#3=%q|wjplk2 zQclOm0K{m465?(#c#Vq<-~*o3+!MSJ+g8jgC9TfjOaj1G@5nr{rwn_Uhk5nU%`bSIm5Q(iu4uLmN1D zJ>{<7{A4cGO;yZo`PAi{y$X7^0N?qs+CSSqoj$499jqUqGuD<6h^{a6tP#97cy*$a z?=Aa7b!07<7T%6!&&o{DN&Gh+`#Vi_CF@~13zw>VUun~gq{k7M zTi36vjddsP%nOYsrA90SiVfZEY zEv*gRTpM+Dz^hUxhKwuoYp*I#B!%fBqc(}hS*)cQ#Xk$g9xYau4c*W;pJMsbuW^EB zjG9}Fk_@-9{GRcV7f6gF^U`Drc~eQk2v96m#rM+zfV1S zBzfZx{YUK%Mgg=hRrWuJq&e-~sC6)`;c-Y;GFd>uuR=wHnaF?dBWKZo_dwc!7azW=Q*`oGGD;+g-3WC~r7 zMNYp7$P?ePi(85i+m-y|Fvy6;|KB2{k}*KjDHaM!GTpP}&3|P^9y>UT4@Fc2vGm{> zW98J_h#T9-ETu%IV$CA4I2dtrYINWeEhCiQS#`=FciltBDaNVrM#UoxEx-J7Z>dmi zD{>SRO&K1z#pG)q7Y1uQtTdTc*5DS=8S#(z_2#`o1)PtU<>qsMb8I#UVvh*BSTTNZ zgM1Cr3QvssLuF=C#bGTEN3Zy%^JY7aTtjc#tGSH=PK;$CWFInj9g49^u01<+F z+O1x5r3AD*uuX1W`oCo@S(lBPTjau;duoAX;(mXE7iXfm@w-Of{a2Dx_NOF&x~kjf zBL#We%FN%x1k{GEzKB+-)QTV9PGJX|erg2;&%B7OA|Yv#$znKHO|qoSh{8%gABwf32EVYV0(Tox|88 zG9!#LY5;;?JInF~r~Mwq-%P8G{mJF@rJ^q#NE~v?E#AljI~_s8M3}nsogiA%dTEU5 zP*t5BL=n~!LSB?3k(tv1GM95ZzAL4LJVJWwbJ*+oo;7PY9p$o@zYU8eH+cP8yq#7Uc*>dc@ zrE9fYB)oF*bRn*Z45~MrF}eHb+~E-a z3pSSMP?T-a1qX5%WTpw>4(}_(m-gY#DS{+|?f0%2y;*XJGBoi$s7!$0L(C-8ByQ0Y z8uqlhlIlAD0a3h4gXV}FtFRnChyDc39jA?pDWi4l`u=L7-YOK_tu>)Ey~7VrazF7y z5|FagjxFlh#=KQe!;?H-Dg%{-B})m2C*Oq|Em3Q-f#a7|X=-E8_cak%HZl{ox=sUx z7%HBrm+-vBuD3|6(emR#0u>%`Mj^>@>r~oF^c|v)1e~jtHV`1(=}H>3Q#3f$0V;51 z*LkS{mn*aw$ZC=n&S~xt`cd>q;`WS^mkBR6fg-~~K2=DJ%OUsE)pK9gM1dcOe%TL` z?8(ZVYV6q_kKSUrKDi0@c=SUM>d#6GG4uaJ3f7xfSB)7-+<0w~982)h0IabqqQow5 z6D)rSsz%u#QmCY`$8HAFP5^|+u*Vb4C>d~7SDA!wq@Rgp=5B4o;A-uSjZw6Jd=$Ch z+i2%<;_#kKRym(YGWElYCTuc_iG_EHx@`4zj`Q5Fq4A{YDLwkcR=?3;O>u|6`P4`4 zl{4qQ^P&pC`jmzy?@BdEGxA=3`PPVEy906hX-CzO_63G%E$sJ`eUHwtwW=?{iDI5R z0Xp!hJdrC!b&@ruOemwYQim;48^m5ZKHH$O``%qoYv%Q_@AxOO;bV@Ps&C#+(qlJT zbKMCc8N;qFKPeu|rtyqj1UL7OjsS8;Xl8#m8I@4oj2p&%op;2~5)fav4g<&`vG76oxz{oc#$#t`$_pgOz z8-qf|01C~jxZxkrvA`K+j-nB7Kvkuk=Bn;hk7_2AgskWypdS>>kPg|TscB4?qk4ry zlSE0aFf^=wun^8p<(QW01!qucW8yX@W*5#e=t!#u6*NAw*+;BeD*qVFIPm43Z^jD4 z7J%X0e||-Zt>r<(IR@Czt}K-JbqMQ^chh+$bZ|{50X7M!+mz4TjHpA_S}^=C!oE5# zs=wV96_hdnaR4bv$w5Rql{2c$h*silQYn$3OmG?JSp65o;?D$Ou!hH8%nMn$!$UlXS1Qf!iQ*%3s23nQNBSau4 z_xolz`*khk4xMDHnmpA}q32h^WkSg{Wr9aK^z+D0(3{^T#KzTAps0oi93JbMkp9Qo zqdb86=cqmVl3(>pnH^|_3_23RJ(^--{wj3I5zUQwd+?;n{$71!wUllq66Da&ylSu( z!Ry{YQC{32DS^JwWvED#K-%#r>xa&UZ3L_oW$;8(t^po@3YF`tb9g^y$?5|GkH7o5 zHe@q1J}P+PN0xfYpF(BywXi3&x?@Q-IZ%qv{RPg!XdIy7=$*YB+&@mn!#rfXdd32bruzB@q#ZjS zpo-Lg_~sn|@MdC5BWP2g)E{m=wH;ZX2nD6CB(xc6ni5awL`QRcf?KsN`31k^^9&Ea zL}l60u55`+ii%l1->ez>(tw1-oM5npF;v6Vowh{Q63*Ju718A(B7Fd00VLuM$9q%u zPY%K(5W;s%uQ1C=2+PzGn^__!Xrqe(%bj1Lp+Kby6n0v0q?A73bC)i+rP)YPko zjb9p049^#D8iUzwL1>FQ0JGBIydAz1{0Qlz*}d9i1%Tw*a$~u*3I;)Y`P*Y3%7uVK zd;f=2f*d~^4|~7zk~A)23mC$VilG|06LR?neIn6)p2Mvqf87*2#Hp;b}Fk* zYeoVH)B{0Id%Gan?@_Lu8ELWBt_1PjJ;eUZA6Ps)Ii!5eb2(8}TH-N83u^bu@hP)5OGjU!vV8>vKaGjP zDm8~ffO2F!!gdO@bE$EG@CU%xAXci(S*gvbkB>_9w6SjJZ@$Siz(9?-uY?6-)edYAVI zck_Fdf9Pev*wgAt_wZykG2V8LC!y&^r1nM;Vyz25-Z2~4UFCHU`zn=iF0sTLC}-LG zmn2p~qvP#)XTU>P%85Vgsrx;$dZlPcXw&#BE!t}%*Rvg>g=R#2LtsUdt#)P)5^+BS zp!eN$w{yjmlHlg*T2puX+O8jGk>;%vrwatm)_vTE2+#KvnHqd!y8CYKDWiRp%84~@ z-xTc!A78mWON>(NRGn5Gj4q3GYx_9DmT^W zoYJfgk?-up2M6MsK^Q(DDje!+FpuMfnyZSw#koD1sE~h1?M`lW#gV2}1+;r8Jd09$ zKPm=1vid?U=|9++29>(SE)nrpgXyzghxrc8v4HLo5uu*kI4P&aS>`~3s3)saob5@C;JXQe z+uz#rLu(Yw$)IuCJPVVGgtIuGKjJtsQ2QKJ#_lqf=}Cv&l-BN+MAjwQk7B{8-(|^K z*)E58elS%=GG(OpcAY%*FX+6Kb*m4nNK{_C>As#@7!Sc+|03IoBMd3}#>tVi?YedR zjuu+R{d=pEsHb%1j0S7_`a>#c$6M-kSQAX~6VL$zclz^72^mS?SV|ACu*+a4smHh5 zX__q1Kr<%gxV`Sv4y*YPA+rt2@DqZN7#qwCkr%-fOI@kVWTNr>WoPz97I?KPYyj~}KS5Y@f1Fj$TnE|q z6+f;cVd#J)#k|LORX8wxd=uNYZm_kGm7>>wi<{FtXJ4(h8W9P{-k5m+j0BmnwvM1 zWZ*0gLGbj)*S!=LEmR}&u%aLo_Esmpf_<-LVPZ9BL-NZkWN}H6*!-~pk}a}94t`J^ zWzI~vFfqa&v5)G<-|~?h=&JAEos{3$kOYrXfe?{^cn8ZtoD)B1(4r3T{7V4+^zU9_ zq>qV_gO}KtkJ&>hL?PNxi?%b8Gh;+8eP|#2s=c|@n2%5B8my7r?YZw{(Gb;13>2mZ z#4TEvqr=mhY8p#*&{Ui+%L|4}-u@Zx+Aie^DYi&nQ(_Qk4-IBSc-SiT`1v}F4yH)t zHwp5{Fk@2VO=AiRd(B}jTY!P=f(#UGtfx8Eu=IS&;puU`_Zn8x%F?lEDxg{nB+@9c zTG;$m1Nf!Fk)cEmnFs{+ki{ePUHlRc5BmhlLvEjcXb$XRuruV$?-wKC(edR9h^1pF zf}Y`kEGXz@dL0~}8(*EY7#z|k`nZxfO%}`x~LMFvdvZZ5Xy&$ z4xtO1r66kK%}e%HlrQPV);A^KEFrz(yIpY6XkZ#l@ChAH=jL}Vq{~RjzdHexJycUp z&4>Wp`OnJ*^v&4j5&BG;Ll5?gZ^wQrTb93?zl30;=1YmP@i{jtaZX0|5K(Pvfk=zss6=b@VW=wNplc`W@nAL1+2u{%ICwHLD$P#*yC zF>UK>j!*sg8(UaDv`ax?cU!}-1%_l9n^-^3tLSrFzD*pi-{>Q8yduuE>&rO2s;V9x zS~qF2r$Ps}b`lBe-Sikx-69{?*9=#x<_layCQ!8uUcccB2m2sgIRuuru65!AgxpN@ zbNp`GX&TtQ!%)Q4`BhunzpI>T?iz8c&0PC!Ix|vYOv)VVTgk@g`CG|3!rV1 zj^*#e#KWZsj+QM6{0dx{j6Z2K*csqE+QQWiAr?Fp zuxaC;d0>U!s<@cCUH2|vDnOZ`IY;% zi12$Z0@{2~vjqc%#!>u}JC6dT#63Ly2yds=*g(!Rkz`&#tsp-W?Y@EP^oid2?$h1g4)h%`KQ^ya(r7 zzi{V25%Tz5e7*D?hfC{f(;ID8`V(q(*tg$e4L>{XUtpc4z>6)Q9S}G=PIaNJhFuJi z310q0)Z%z1{bDEt7_y`VP&X_is2u6=p1W;w<^z*U&kOmm#RJ0V11-)h&Q&13iC``F zfQs>wjQ7S5hp-du7Cc_ahJVS=W9LjUPuT_lQ;U+kZH0N7a-p;FlWl?-GGNc~u`|KI z-W}9S2tn4Glc$YN3I%sDx-I@i8@?}R^AavY4Ipq32_mmI{`OEOY+@$v1r%|cDd6T@ zBdX;*ffxJ&ik16&jO&&CjZ7$%2TAoIRE%;(KR^GFKh8;S4+_o@6wYRIDJ@}mFR_X2 zDowsuE+`e1LD8%JzW5TGRpk<2{uMVX_)gUuM)A7v=B*@k#GyjcJ4UoO!9b#+H~X{X z$E523*6=@g@IcQIkohX2SU8Qm#$WJuz~_fSQrf-@c!9Fy6LgW95XUtpf1+zIp0vQEhxIEyuPNKVsVj6SglNZXe z`d-=@*YMg^u*s{OBkK|WxN(I)Q*K>GT3JHzRRkm1PKBbi zX%Jqo_~&%=rm6UV+53sF>UP3*Z)mmauU9ty10I#3Fs31B%xo%4b4>`0$+Y;-JO{3Z zbMrvpH6HXQMHbLn(LA|~6rZkky2&163~1HH-yZ{n;EGD+sQWJ}Sk^JNcnth+Dc=NL z5_g-3(H}{o=sJn zg_DhfSh4a^XglxEFEa*UIQ$-miDNyiq>?iwC6G3WcLftH0yk|odR|h4q#$}{u@|Mg zj)`>Sa%UyMd}dTX?93+z_-CgPH`*^RS;dm}K0-$I+?u{k(EMas6C#49%W8ZVwRi#~ zmKnSnj#Er0No#eW#CoU6k}b-d;!~%K7x~R{O->OCQ4P|2B5)MgIA`ya6(V9$e6kuW zKZ$6w;@fd*PxM=L*3z4NMN0alIFG7S^b+>s$DLqg%@UpOTv)+VCV9Ycpoax5<2t-R z0lbq@+sAb0ra`w}pO!%3YWL3wOw8~na?+gn)s=Odqe6XUzCKy+|pg-l-8T>YuY;l-tLa!&)o+fKD!MF6K9tqH+los z$uRAO?#xe=Gv2x%7M35h4dxKNzPH5#FATZH2c+N5fw)*N<9}M( z7P{9DkVwh?%mpPN1O!QR=DS=qL-u-1jSYKT!?Mvs7&5@92uP{Se*oO`fej~q0gn|l zmWIc%O)SjH5*XO1>8SgL3NikShyFCfDfi)ZHUNhCe+9bzZ4B?Zf%|O&`60CC&vQ7Z zfGr6Do?#LBKDYKa)BSG$Enxrk?*TaAq(Mk57ITvTkw`ObvgiKKq{VshXDHnl`U+ZjKL!302Sg?& z=m2pLv6Qw%3|R4z3|Q<|<(Rr59|~7vwu%lhCWhYdOYgZ`*RXaCTrD$yPNj!T*75MY zwjD>yHt(tatP3lz_`BS{Y6j}yy)^etYXtjFpTM2UPg}yfH!snTNYo#$`Fl&iNN0f3x(m#O&7WI(TZyyMG+tfE zq+Kq5+kXPvpWeyR2-R{e<=CC6O7A4?N{V`s@n$VXH=i+>UG~1Gk9(Td{HwKfdhB7@ zum73duz^|Fu3@2}B(6-JuOHkwpy5-U4ZJ?Px|LznyxWWaQ~}E)wYI>?7Q(##J@bpN z(Sy-AYUAEYt}YHGVK+M3JN}kAxRU7CmJ=~*`q!2(F>Xycrp&nwCtr*G zBi|ZV-#B%ww#d0BT1qQ+;!`7NtX~Fs<-HhGW8Mu36p&BBDk0VEM`MKiq`@VTCaTiQ zE9>06=Fk#&BL<;esVe7!?MSi_2X05{3Vyr7nC!DdxEEvlX=$$5jLi>tBrVMm2}GYfF-1NQhr2~^j&!$16bF&(pG zt8D?pbMFdyl|-q5bbD#f;)BabX3TV{+l%Wp`hrWg1`~9Zy!|E-MyDycuGC~~$hLYG>nE=- zZ!=XIl;6Xst3otIcXr4MFz)yebZ-t*NQ#dF>g@t+WSe5_jEli1$$RqS7AIEvXT^)u zl^SevNnj|%O>@yW zK$T<@ujbKzuR=Mb4v~_yy!s zFTk80d?~pv*Il(Cyab)szaprcxmzW8^royVV0S82b0m&1PG;6Ps({?!*aI%jk>Hl7 zl_-og!w-4@?NJc&-U@EfggB^tOp$rPs;B#dimMYnUu{T#WX``F{YEM^_8k|rY%t4; zW*}{}BLxQ?KpR`H#iWdNPK9{BIK)~Hqi9`^CcqlsMbHzT>6LVxhvT=ZGtT4_-XhWxqMQY?WlIBhj(0(ewe3#9KCK8({+*BBiP{>^Dx+l!G(mkG^b+D8$3#oqh$$ zk4$hs7Tp4xdB}6!D^a{bzv*Xqvp=^U0nR$Td~0#S({;GaamNE8P20h-=eKs_j|Ji;XL&0|KnykG@{#>&I~ayti%k^(3dFAdq2;+< ziIGui91i6iJT(k(uMSn@l_(ruKn$N2o_I^OYeOu)K2$}9j1dLFYiQZpLSP5tlyP3w zQ<6bK&QcoW1-T+%1+ms0?s8M^4CfHbizN%KOZzvSkA#y#cyxeHy)|k#@vO73NVvG4 zI_su{6UMV$3*kK_SE~{sCLFkHx-~h-N^X*AI@Y>L7Y@bYY`Q=_Lez#@+F3UM!cqOA z(X3<%3xo6>tv-qP+uE=+n5Zoi75yv5(&eI~w;Y!l1KV1Gz@cEQ^zfS;Gi}#Wu^qh7 zDoWy!32|NyJ@tbTnB<1_q=bnrF#{=6i-I9puge*%>gS(Skudb`t42AYXHTOkdHaok zpnMA0C5&w!y?9BatSN#;EChkcI%B)bPYNZ-poT|l3=eO8rAiBQDRSV+8gYGN1LoGx zoAve_x6~_xyB2cZ5v}XSy5Eo6Y_F$6E$vBQM;3*6m^k_d`z_^`)*(?_5{e-robT+$ z8COepivgBtQBKc-yBtgzh6EKOIf>L=u+?rksqbOIPs%Oos+?jd1XBg60P#h%X52Ab zU^T{ISZQ8|q0*jFoSvni&*!+Uj}UGbA#swTddi||PCfE*5blO%z_J&RYUX~Tpg&a2 zaen)C&s;A@hA(2S&S+rNx&{s-Q|mh%`}q+x685DbN@xA(OH#GE#fMmS6BzR1MmV6Blrp_7h-#`j#H zEMChI5~f%v1Untv=lqoz0XD^a`z3STKXdqM^XeA9lRI}dj&M)bVWOzKfJs=nxCat= zZI4v}38%@XRnHytsb+2kmBYS_KD*^BXc^w=KFxP9jR4#D(zFRbNy6FrlK(ChIZoMb5O0mT@`Sx_oz?KB zdQUvsTyOlOffm_`Y|tM?Q(p%7>}td!YT(ch6W{{1Gr6!5L%88vQACkn@3E!vLO1zF zz=uO~@Sy3Qi;gXShuzQ83ezrO{*(1AXP@2xlTc#Jn+eK!sj%jyY3yGeLd@|~Ihxnq z<`4@+ekb*gq_)-MduPq?(uHo8vRsmcOP9cQ0C5DaJVlagGzLH)w*auzU`h8T?r57< zbk|s*=bh3@((!EW9Nmtf3fAYnSC0Kj9&OgCuA2=54d&N`+gkHSx8_5^j;AkA#?(e( zF+h^741jQ549Ss@1n&cy;jt~df`m)125lI9lk_)6bepR{PEupn$?l}>cxg*m(=G1Z zOwOT%1Je(RZC=>pzuN;j!ZB5+DRY|~@9-A2&WKFj_FBiqCGC@10(g|P5%x0ZdFNAq z^@7M!*kzkk)Lk{)i^)uVYmcl$=iBj|;uKM@^;ECX8Ws}PG9&a&M$0%cfGCj(lGH7X z`UZM>kFJjAHe0likP?D3z`%zDfHApJ@m$$?eoZr%%~rs?x5`!xU2r1Ia!u@!+jj<% z_9s)@_nFX}6kL~Na-Ox@`{1nH1LD2Kx`h!QPA&J@k$?s-_P^6I^4*|e#~KcNC_-9fF2)y3H;@$#2lz)Pn z|8~0nE$CSY!XDY*HTfXiMacKb#p7-+BGn!j8s~&ivSlAsldJc_TQM$FHjq~^xg>T@GnfrqjV?* zgUXyiNdRWxoNpty_2^!yCJl&5GcfA_Ner|F+Ln{e$V{TuQX zbxYK#Vb|AHhhI8pATo|BAFoP|mfRQWt4->vN-#$SAi-50h2Dc1%je~{g3<{c(DB-U<@Yu)sEteyyCr~t zvXA9nu&kHMdNuz>K1%Gq5}V)BaV}#AG-y4*a%Rp)=v?<4*yup3%5l;jQ{4Mcpe%#+ z@aJxa+ICaEmNIe>gc1(Jrv^+>T?&+S>N0|9$!w=0UIF(+@R_`E>L>p*uofj9hE}Gi z5jkTza#U7>=ly$#4W+bX$|7k@ zsX%4wNs^mvZj-bb1}UZAKUptZ+hZ%YJCoxiVnPOnMEy?n5)j7{6;0V|cQM`(YE zAiu4H$O&4hZ`u&k2l6z$?j;Nq!2@GBnoO zM*<1M{GG(!qta#LATdhIL}sF$pboU#yBW9F7qs74mYOe<8$U7y27G+sO+i6MOYlUo z9n1MK`Rl1XH|H+3nFY0Lj0U$a+T@EVZgtvmjz&#;^>pobsK*FMeDmi+#zD@5MOzz# zlwa&yTkJ4ltOtQF7AepYeUbU4?FP5!4z-lDCUURVPB?Dh?#BMxC)>pZ#hkf2Q$xp! zN?=G;#gc~35IJeGmpct!aE;S`w(I;P2wR^?K=G}=_g8qwPsUgB&WL6o;^Bb}nGC}T z%aXx&A71D+^jzyg%PhGt$SsDbq+!PJwW?Ug6PtLIhe zN_!dp^OvnwBEB4Y$*K^8u&}I-sj9i{)4d^~{CYNSMk-uyK8S|z4>HQwSd$tzz;h8Z0-EiM?KDOO=Kc3W7;O3VR z<@5;@CkvcjnW_AGAGs6UqBAu4q3hs#vPdm=EA23SqsoSN|NF4Y?;A#;B9Flwx!#(+ zpao;+{i_oYTA6-K-ZW@ML4wqVTmUBf^rhgI@_Sm{g6uNcLerU*P8jLyAsVo6chB?r zOQk6*Y8XY%zyvwMZtlIwrU#8F1=+f%&#kvzQHsdMr?Kp<>=-{QeNs)}fG~NA&Mlgb z3-qMvJ`##}q0CP3*Z&Tb3FMI4-@spyS^Eh4Wmsr!#n1JO=F#ir;({79pB6U_@((NP zF%d7p?OoRJ4!FboFAD8PhD29BP?nN1{3_?j0*5EsNPW}!C>Ti}AWO6I3)Oyj&LQ*| z@Av7xPPfB;RV*eFj0`f;_G&lHa~_M{M4xhfm^1VU;(qY-UCy%^hA9JgF_#)Pwhsr> z+lG66zK)j>w3>nxsNcSdBUEA-X3GY<{jV!2Uf}vrLdvHfkOn~?qd#;0{hKm>09=}q%Lm}w{^*=USCUK;tCSK`OC-20uq^d9od(xX`eksI7L0%}mA9_3sIqn# z#aZOVI>rIKyHey+rOr&oM;H=4cNDlcRV4CT_dIE1- zK!OCE+?~S+xM1J6RU!F7hZ{$K7A1jo;gh%Ksr7a!#6OqXAyHlNg2pq#-toa*i(|g? zH(7yISN_;z+Cm8=+c)IDU6W)6pu){WgsN8Tc5A4|*U23AFS>!%y<}Gd-Sej&sX6`l zWbd#!62a?mY@|MhXWR6Iq$fP*z_??BQ@uJ>&(f{Mf!I)6E8^t#~Xi~OnKNNkGMK2LDW}x-C)xDPjrw4QN!2Ey8_TgQIE;qNS2!@Zo zgJVjV5TgU7PVu`h>*Bzn$)Bb@D4pPb=r*gH*#3Dn?hoMrwjwPTg&Wp0LhN4EyG=Z{ zpN-fCk4}BAvtgu75L~ibS41o!qDFY)O2-U}z69=9>8g4BoOYz7L+~Gr34h!#W)7<> zV@NG8vwWTU(7u5=9DIO;05I4KH3|f?(gfaiS+Z2J_JwouPtf{Oz6z6-+QvcS zyCq(t@urA<^@a*8{B{1En)yfAns;(vTw)DX>z-~$nj_NOuapsV_W)y% zQotd*nRfHNl`SQtG6FWKxfXxOUH&%7mOU&l%Yp@+Jq(Vd`tOs{Nj*+6ptQ{biOkTa z(h`S2Cc&-yckrgQwD!Bn|a(>Lm`=)BO&d#;)wG=5jg0x*6Ur_#XJU z_Yj2Nf4eB60|x;g2q~AP`Ib2W5m{0fJ;eXLur#}{s|Yh0izyozRmI804W1cXYd6(E z_)NbJUcU1ELFV+0&EA>ImS9aH*311~n?MiTU+Xd%_%U0{8ge}5q=V7`m5lP|?&w|# zba%}ls=9ub*sV5pz5U2!3F%xr9PA|kJXSzc@k+*s*s!Gwx|OT7)sNQ=`bqO93S7F0 z1>9Kn+-m2PT!U02cia4)@+w=j4<7QzuSp0xB?AJtZrs$OdJH62Qc3uFd;ZvZlz55> z2v@8HGexRDS$+HWXJCQw2XGWrTHQ$S*M=*z0!AC>z8+X2{(%*+%cxIDAzt6HsSxFN zCWqM-?`7gWtI5kQa|I*{gPea9Ik*Ise2*jzc|~w0w}*jLOJ)WanqVCLB$WSqy`BaZ3!df|K@aJViEZSM1czmc^lPGn zA^m2qP&5%3UY~*~%a!i2t2EauRoHMg^I7UD5C7UaMhOwm(74po25YS5egN&)2#Ujg z%^FVe#5`3Jx{U$1GmkM7B^`dY%;(1Y;=bGsa(`!aMR%;BF3olM5yn19v=$`A^*Oa< z3f}R>5rRbe+*bzX;6S~!MbO}RB)Fqc==3S{Mhej-oS8>bHECs@$xX8+d@x>|2Zv8; zJliP=ZttD4plpu?7w%MB%zerUJAtak2-u@p3v-agLQ-31pS5{h5oDKq9OlfieCs@k@gwR<6fzN8tv zXwvUX37LJS^NgMcs%MeuBtYKRGrJHBm9(%fH{MOucV;imf7`^N5rRcB!c~i#N7NHW zpF=LeW!CyI=&FSTnTu+6JmnN6&g%U3yM~1$g7*uyVca_liYM2msu2q8jN&y z%E}>S&8z)rTSxynk5>-~k(#B0jXdK}zb>Zr*&z9QXaUkjngOhR(O^R)xz%CrE#_t! zI4Amzvv6NU-xuICy`z6UIV0#y!iUx|Lg8or>P6*Vvd`O}<=1g%CQ~Afmu$er2^a$xqg>s~>oF zgKkj`k~gc!C19m`(6g7~Fs4Ug{In3lN^<=D-Jh2}lvbQikI5i8K^bpR-zIoDLcB<^ z#1THCC~af+H;Z5Dlow)<1CFxH%)fp6V(yY3624qXbmC#@+s{F zWzoeKd$Y(ikdpL)g3P^AN7`(Nb!+;q%>=m`rYAu+jQY~ZT%;p)?qw;i(PFSt3<1fO z@4}GcQ@=#4FMKL3_s_iD(k#b*cU2so6;&r;rLgPhw?bfqZ%mBu(R4W(yHm}uMn3F^ z7UYFn9P#6q!-ia=fj=Vz_SWIUBQK0r3P?N` zk|^26HQK}TSLaulf+*^+i^qIL8xN7xRx3K}C=hm7{E=Q_xxx(?T6jn{pW@drEN0>* zwxk}RYo-3SBtR0xY3_;37)^j@fVY7wO{(fE2E(N8{CxQ}M=_d1jw#X!VP@lUxdtyE zUEv22B6)Qq0ae=$c*SGLzm&ZD_1lCt22W~MQ(0YJ5j#w#`0bSLr`nNPOIH*J;_s4(LVEqPZio1nFZMW=MKC9n0WXZox zd);7@&SWT;ZjSV?)q+@U)meYKP(b`;sQ7NY*&SY%v07sdCTTg$+~ipZr|&*MCH@E4 zbivp6j@H~f8A4NH;GZ(0gOa1ZUz^8%&nwzWJVc8!!mX$E@&c;YJ&19kfwU{a2b7QK z%aSn}A;>pC;FgdOTjiTK+FP?oKFI%+*>ra?5_1`k>qj3zT6reQc%N)30y7%byz^8I zzZEy~u@;uS_%M7`@%6yXa7H1?Iz<`a#rDt=+`W0ifa6Xk|9;`11Pka{oTo~0zrs2i ze-aQ)Qybm#TwkGCx$@$QHNS^zkVL)eCQzdwSOIK5@}XDdKfsnoSu^ z3waGuU+|JW?|WV{Z8u!2S*81yx^Mzx9C^fllSK3TX6PDA&+FZ%`ESxZPjmL^!irR< z7;k2Z76THLO35O+r}nh1cstJO2G=p<7;1HMuspv>Yb}}hDei`MtB4s>pUUnP96$eG z&_}&Hmh51Ph(7o(kliJkQ?2skP#>hlce$D!5Y1fnjiaOHHcHAYVZ9G1FO$3-T^5$I z){}myqm@B#6qt4~cr*F}YjzU_U>nCVcIcx`Lj#{BrO;(WqCV6Lzd3opz{NC<-MfOc zO%@1w%8eNP{mh9Ntok(}Co!T}I_rtMQK)(vkqgY|2Xn!o3UHD3_-5U<_xhs_XL#lO~Ep!0up`-+&A9V#{KU9wrz4#GKn&%r4FtGoQ!LPU}^MoFHltFP!P z^r<;qC;*M)`GORz;oa$s%o=&WuHq$ibHuIG_1I|u=4!~$m9qPYdeS)4G19XJaCr0i zR~0;c*6r6B^>3~p9+T5FOqnS=T5*)C7eGg4y>$sBikewy{C<2;g*jQ~Cxkix$^3GW zaG?=ZxYk%6b|OtYN>u8KZDpg=9G!T+WDgl%3Oru*mAKz`{)P$W7atHAW}xlw8HyKn z3ojvkAf=lm9p$0x?zpZI@oD)C<2CzAId*AlgDp`98ucA2+k` zBfsiykb2My(AF2uS%*1|C712c%z_b=1b=h`EctxKKf(8=&%I!z z;8c@3+Iu4&U~`m}>$!jR+>?Z-)O9kbH>SKwxQhDS<->ub$8btdgK@H2rx`~XLjk1- z&-EZmUkML<)!yp_7XhSo3{!03Gk$8B-*Y2R;2pLHq!5eQkz@BqbP$S2YY)DxC8#51b-xp#2#I^RyjMdO{ULmT;-*i0Yjw4=kuUT4WI$6c4;b?H`kjEHh0OfbYD z!v9)iII5mOVqP5ydoaHh< z$^SU?-Do^inIOHk_M|KV%z6`XV^6c+8+5$h6GvQpEIOb^$4n7{-K8*ByE;s0gb9uT zb;n(QH;bs3f{MuGHjl~H?@J$V{`^k>_b4&lLDezVqnAM5pVH6s4sm4g3c-Kf`}-)^ zUQ(+W?T3fWgJm^V&)EwFovzqO@}_In$+#~?+DYN!ugIlzXCtly;z@p5h%iToTVZ{^ zeL&o{Ie+PMuJ7=Yyg@BtvrOMH;B+C{kGqEa=qYt^7eSB-7SFSoBzE3%oi2|Gm}mg? z63Idtc6KMdefIhn)yCRd1io%(Yw)%~G&uUHKFN@)AUcKwIMc&$w+Bt?GR@#?A-YrO zarb3*%a_%leXJ1 zH~G;tf1hPj(3&yA$0TgcePf<2mAA8#_|jOYiBB~+)Ck?z{SEa=LKB4&(#?<`5&fr< zo;d49>Bd+cT_@&Fx0l9Sj#yWt!D^qo&*?V$gtg})2u!C-%m|;hm|$h9^_)2pUXh&- zRX|94bzb%KC!T-!^%58y^LsL-I<3)RR(Qutc>KoBg<*E4sr7-tM#T78ysnIhLXi{0 z-QWFwD@zEE>u(Jy6p=J%eoQodtQx7OC|IB&YqjR<36Ud=yx=W&w5u!&l{Gbpf#?^! zsp|mG8WyD%oLhWjru?q8ka2Uy-5+t7Tc!q%2QYGXxS@_ka79m*C6R_gTsp;Bl?9d?3b@4>$QeaWq~aLQ!UCR+zo1bHuxSf zIs=a;M5{rmTEUYt>3O%B&EO= zo)ifch;<@XBQtu&5=wpMXEP{Y-Or;jMcB~Rblh#1s_79(11Y87^ZDIqA~IOY7Bdy9 z-114iD%;rI_6#SnIR_^wc6yoHfz5sonL6jj9!u?w%T2qhTj6G&oKt!TL0(R6@BknFK=bwezmWRRa`vhTS6`XM2;)UZ zhE4ih!GS;>E(84cVN6pp5{`4P1V#KK)+y|DYq5XVvcX+BtiTn&33oA^4MTl;KuJz( zuquF%G6%n#mkj1G34v$fs^H|lAL3r|c&hp@tgaK>X*9lQst!?o$5NE$WvLTlxPdi; zeqcoGT4stg_-l9ua_{t^{6g4*Y;^?9id#TzvFGi*om7 zcx@l}TxIKAHv;J=LqrT1DO>~S3H)*Nd2R$0XnT|2;)yl5e_-c^+PSKk+NNVXL;7fN zkGnbENWxKQ&~rR(Tv%engQ+YT=@@8e1G}hIqP?8}QDpCZ$0^>uc0YgpMHmkLDEr_q zs|En|Pbl|4e>4DoLB{<{PyxUE8^hoKaZjE5_BNlwmNCG@0iwoxD6eyGk_e!`X9@nH z{qFz8{{r^^;j8{o3e1RyZp6U0>`(6h32<~eU4R}PN#)NT#;^4SD&+Q2$8e4?(nk8= zb0)=eRFw~-JV8Qwi}??CWLMizlC$&Bxh8q9Fk$)N6+k%+13k)L3T z%s6eNq;_)RF<9m6-={P_gq3ZRJ)Xj#;Lb+h$R7C~m6K zTxR5B02ZizU=l_;m3#StH28sA_U3}FL3@!fm(b|opn5}md0PUa9GyH4*-|xZvS+<# zP;c`|xv5A&M(`5N`DaSdX_hU|onA)FM3Czep~jyx;ttQYQdk-p+dgE8wrZ%DzX-_J z3J+Tk;{3+c;8qnjc1abAD_EB^>%eNs5kQ%JQc#uSKO82uw~led+$;S;ffjyh9=h;m zAxRGQ%NdJ?y^xSr0XnS2`MGH~u7snKRwkYGIwO*#hjOn{)4wK@iaxO){XgiaDbI^{ zPVeOYVWTdmtK#DRM>gu#tv$5m@}b~Y;M@!G?cLQRPfV_;P-(^#e>G=4?j`6!-Y71;s&EDG<-+u0Tpeo^nh9mto5O`(=9WcVf4~Z zuaFanv*&w2cKuBH(Ei-B5clP z+;H?Y$tWx6Q;&Gmd!M&GAf>Li#)FHfa1@(QZ`U!%a54YVMW3}FZE$UNgA5`-0hZA8 zRV@cFmy!==dc(X922YE>Gx2Aj3Ko^Q&X<8%V={3+mR+($8LPtmIP!w^#iM}|gz2W> zx^IF@Xz(IT(W0vL2o;TN>nmyBG)N+O%v)Gk5>xHJR!p&}`%&p7UGIl|8$AdioyVi+ z>k{i4M559vtYzJvbe!w{y~nrbjXQii!>1eD@8L9RBi-5IjISHtOv5QNFjR3v|L;1Q zOyB1CUl}j*a6h8(crjSG06F<5JpvSBR<45t5#SIq@Rqj|*ij5_WtE9Dg18s>IJ{$7z*59pkkoRPu>`w=+E2Mh=2_yOpZ?r7NZkg_VOJbMT4@Oz?+ z1wq#Cd!j016_t8B_bdxfTk(82L(K4wrDS7>E9`o0v~Fqk4slnMbWHu^S+ld#bnW-e z*+L8XKE2NG&1)FiE`2Qgr1yNBPG6_y$^h^k8`?UqD-NW!u&wU6ghOc7=9}hEv7Npn zikuAJae|5y5eFjgK5^pk#YyL{2#s=dfwWAc2xMR{=)_3-<=A$GauP7!`;IH5ixoa! z%5@*FJ<8?^#WqG&U@{dq?I$$pr00IOie!s!RHhBjNJgF0%IuIAPb^RHhamyu66R#Q z-EERYdASY27SY-D!j|RjsJ=e&APg-V(l{HHpa)2NFNhHGH!WQkX~KBcQ&Yvs$1PnC zU%kroph&3^8|b|Bk)kY>d`EifYp55$<2iEe9^V|oDNwXIR)$#4^vrvTaLETAnO$|U zU>^?DToH#8$a$Z}l3HzI;;G1w4&R2+3CcRVxf8_y4`;Z%h3s&ik#akz$kB|Zr9q(C zCs`MKN5u=s)?4JNY$bPHF? zGjtV$m9HxC)K4>6(8C-#4emKPB%9E$@b%HKGg5^bQb&)7lOeieMm3LL?~fa;VrM+F zweoEJr$Ga6_>qq}Rgc9TY3pLZ<7BDHl-10*smUZm^wTT{giq{>TQ=#o*)3yd3%jJG z-gY;*cv_2ec zCfv@_ywFz>3EmLX_?nSw(Z+QGV@OyFO2Og5Bzyc9Pht6H&rdH_;f7Fj!yQQe`<5zT_zf(Ve8d<(^*3<$sHcoCRyhiXJV$J>^!mc`?sebRHf}nsB3M$

E{lDFV_xLIjlVE@_c&sUh7UAl=;{BS*exi1&J*``qXK7q+vV*!g|FpE}JS z->H(SX^D0|D$IMhssw#8F+^;&!Tw4=UIXIJgnCC0m%ie_A~_50BU3y@!5trbXB=LYVaUG zR?#rAYj}6rfZ+a6ccM^`?#n9t8HZpE=>Z$o(EsFhzc0z~MD3|Ms>1a_(vy03kZxb& zMgYVNpm^B!w``c`Aj44F0SE+~;jk84_&fklJ)a^F3?Nei9OI6?`yp)YMmD~B@}<%g zl}`aCspRi7)(Z%B3fD*$_{F2qvXASoHX?bV3sZvucMPzJ6|~*($7!-p@<7jv&;Wo< zlnp>no!<&2jeHVQipsiZ&1cEG#;fM~%Rf31oH)`a=HF;^ZW|i^1$}bLrlio=w?-S- zqVO#Qef@9xPMec&B243aFg0_irAAGSr?y3%YtrAW_BFv*@@3fYBcG{fx4Nd>N7zX8 zYr4z}+IuQ})PL0S31{p=eT5KU@2?_eGZS9>Xgj$FY{`26V_ZO0eRVgV!BKJEQb6=4 zBa#pY&Kj$)QJ_WTMUz6OYcaENA`*@k76Ynv*ymH`M8HUIjpFJRY}v%yH^nm+(F=4P zrj*BCs4jxx!j@6=J1Ym{O3oRePY@QvyA>YmUl+Tces(9RzN0Lx0QI`Jo!cV~<*NCL zsgUR{et)(y{r+OW!lV#%v@CrE?!s_o`T6w!$ehZKH0U%z}Jp%hEXzvgeY-AhEx$;E&{z z->PSM03CXC94MFhO;Vx6#v*L7X?O|qihycW@O0&eMijgMfiw|brq95R>3p5bZSX!$ z@*S{nj3yvqDZiSO9o*U!Pr33fm3Z=aWCSyHlr4A?DhQjy8-uX$-g^rf!)*-N%ZK>% z9;LnXeftf!KLp=_R*KPit76L*m@zi-yWQ4U2<|(`W+aX|i$3-rzqi=3yz>bVKrvJ$ z5SVkQw6%bwL~cqG{F5hR>5~IXGTjcJL*Bh&c)smrImNCm=@ms3R+m7`V_m88Zn9ZZ zkZO$!eFGif?HQ;uZ~%R)2hg|v7JC{Pd_tuRK0+pNUA@t*LhSNO_5{ouc+c0Jxzn4T z{%o)}3({k5ITY|9-hRYtsWLM@gc=#b4kx!CF8S2I_)%|@o*W;w7}U#v3b&MalhHt& zI29Zn=BF!&X?V&L>=xF;{ndfe-_TgjxRcj1Iu!{IRQO1N7xvJ1>^a_Lr0)EWn1*9E z0=SYAl_@?;l040~lbgtXz?Xf8y}O)^ih*KlV1Ea|SSeljgiBkP<*W4XD8S4c{H$l_ z`$)z?V}`-=+ait~lMk7d-x(2RMt15=)}A~Y(Txd_m}je?gd zvEwKxlF*m@_`o8r=0vY#_@eZPxj-Nqv|oF>+p#wcgrG010Ab1ZBe=~chI?^E5ypy+RO{L$@M%w&M4W+DvIGpl9R-5Ort z@pjn2F7Me$S(BfebzwV7s+}*#9vU#4(>BtBLknJ3-yY!G@`5mc847OLZgCatp`{!Q z{`lzNP@E4s(e<@Nz(yZPYCwME_4Fh2zQ@nl1ck|z5 z%Z-+73Kqs@WPnHcEs-K7+W#h9#3rn@^o|hJ3+=DfFS@ofrqo~+9`ZeXYjqJz>xIwT z&*GPEkK=iAzS|=qNBpO`38e^%LG_))LZXm3vNXws*kyU*wWe-r?hQ23>oqsIE2e&j zdrUBT(rT9hvTG~VzyQCoz8({jEi1eufW-0W8~e3TS_xZ<8qBVDJ&Pqpo5}y8W!>=L zEIoTh?0(&6yc_3&BWWJyy?uMj`ZR3cNPe%yoiWpfu%r9LgtD0#3*oUpBdYAnGc#MW zB~JU<6BYweyqR)^3(E~9F(x*2XcABYliFjfr3lSe2EN4`+5dg3+n#n=SaO-i>&j4?AR@D) zx7AzyMC;tpI8i9RsZS&ue{Ewir1&$7?TC(dd=Y94$gHg^Fc!slrr=J}(1#u6x2Dg` z6be(8G5Z9+l70Xq-~YD=ybuL}pG=>F1B0a-#lk_-9IyuG-Lxb8ZqP6$^B(7?jA=!W zlbKdV;Mv$3B-z$Ro|>XqMxR$l&wlm`stnz64;YFiGsDja*(lrmrdZ~~5Q68BSLJwQ zBX?4iIzZM*7jS>UVROuH55@=xmYWSI(KnxtXUaci*0b;2y&;_bx>JGiwsrapf`9x4 zkLI?52V)!{HcU}!Fd^5%>iJqHjLZGb`iOkco8vBtOLqKWd=aJCCcad@%`*lVqlDUq zJIUFT@nGRMXm{l#dzyfUfHPw#LED!$o4bXz&5DGdD0Cji6yFUrc{AOjVmz^;-{(aT z3X%Uux^KEOruyh8@S~}sA}wlt#U}>w_88xKkpYPT50o2qM^lNN_)U7OLE%q+9Or9N z*s1iP^S2JNR4hl?(FGNQtHd07RCaYG2|-ciD)e8{+xB0v@3BA5cb5%ntQg!(FL`ql z9&UNh@n}dzcXm5E!i}A6atdKId;;7tZYwPYtiFTfoXE=LXsG*e&Jes*9=3K%Rl$68`I~faZUQfBln9np_UNSJp z2yJYA6elCA*z4Y7b=Snk^YPQ@bMpqzh@P@LBa6!ujZfd`5t9u#ft&mxLjI7)J#~<{ zz3JpRLoF3!5~8Z*PO0j>)wZ4V3UH?Yh3Z#HiGke|527hseond#^~Zw1{7(iw5c@J| zvRrf~xBqizU)}Hyp<*?6^TzW#E7&=iiFc^?G+7^Tz28G~EI{%53@{=!lBf?e8)G)I zj2;zenuCV;j63zZgbHMh3}{m2OFYxaIx2WBxI}{zM_w3!}`%f zwceej;U-hNaD0z`ucc0|uBQH!nAr8Xt9m+6F2oxI*$pU7DH<+`m!!a^4qQJXdak2@ z%fI)T=&3gE@Y2@Q{&&Bcl&>gtXFrenZ!JsdIy0kpqfcdS^7u!gxk^oy+V>Rm-s~R| z|BK@fBqM$jTvwrT!2xvrYw%4~(JLg+{TB*;;m5is`JgToB$r|bb#{>qdh47%H;_v$ z_e@}&NciXiWapsL3lY9EenRuwxV6|9J<-UQB!>K^11 zymc{3dX>#m%a-Ri*iOxZ?6EPhP4x`-w!!U)FJTFRQsT=^Zz|ao$kpCi(8w!Ok(pUS z4iEWo1mFYxNsx52&5IV?9EJRG6z)ULB@%+5H1{7`HTiNuC*(SnfhiTgxZTc~K5<(y zssox<*Ojcro70T2;J6NY{IUwWau!`N9YuYEeiaW-gbOj9V)WzDg3DPs{ocX!anWWO zb)m77Zkg5)!FR2y?on-W10RKwY$JjAD}~p>!iW{D_Uea&4uZ?Q^W~hO#vy~g^Ee6S zf!$1+re}Gy*Ps>0KFzIDFA@eSL2tu_mq0fHJh-x`PV3?WF7{fQKYukNaXEVkpA~e& zopQ)DVMO+h1c2cm!fdb20!7vpTEd%1^&4+9b;C7@7Jzzrik)by-FR7mA%%`^>ypGH zorCht_<>D06|wh2PGbW%?r&v%xFlg_Jh3kVxMHOq7xsVD(s*ZzaaaW4?vI)g-42v` z-K!>Le3p#H432Nz8k&xO8f@y%2Zh-t-;?SNNoi4T9SLsU`2h>~=1$ih>E>Vf$v=VX zLYcgYyQCQEL=C>JoRd2<;Q9 zOmjsD!JvdY)g~Is?a%Z<AI#^DB zLkoq8LYu5U?#Mp}ly$6WHx9=ZR`if7qFB?% z$Ho|#%=%*9q;3}u<*h?h>svMLvH_Hz$=5CRxP32+f+79D=!R;0!C7{>0^^?w7H6ayr@RiIq2B{pgi?FkIlgQkz}0m7Od*5CRc-#>#+dS-fL z%wLhlH+_pp7apy?z>qJAlt}T%nC-yta^Ci(Ol)az9)1FO$()T^g43|hc*-)GMa11S zt)j=Ph4R6uNsAqVT4?x&ogt9H0Gv0G{ft##zrE4>IrOWg1dRQ?Sw0Ja%na1moT$L` z1Mca(J2qgVfBxc5E<~u>Ywd~T-j(iK{PlKsmATFewnNt$;4LW)uyE_&VNGN(ufHRs z5o)kkG`RyxS@ z+H6sYGqNmyV(*Ml(~(Q;<=aC`NF77uTOi2Q%w%C8VCrVUz6!xGm7a@XX%_MO4wI0w z?0qyx$z}@y5bq5tS(s1NEl*1Q-V{oc;|U^Mdk7O_mz92Aw#RE}u{c~53e%Xv+aIzOm_Sb%nd};FAef@# zJ06|*YxQek+rs#_k#w-A;a(3=1_inJ;-#s?BRFEBq8~&xFGM`;d=AviVi_TjI@LA% zc=g%WX!rk>Jp-u0^Sh&?W4Jy{7)W19S74dhm$IoTcYv|O${Q=eDvT1W&vFC6`V7Dr zjEFaQrTzA$>!+#^%)EP}<;Re!VN6>(`)w2RJ8x z4-{cb=s03R&#_K#A_o92O<-O@BvF`wu?1ntFIoTwAJ3=1hz==eBA0zNL@5V%D~+5k zHnr3*P8o<#S^=+UByFbYeIUkyXS>MfWnYIR$m|AlrqzKhSvi8`hETTOa*wIAHBB)B zyOY|G1n`oVz>)lA>d!W+-TW((Nkbs?T9?5?nzuQyX9>w*0H00>z&}F|BtoVH_$4~F z$4+|eUoXhy67bR5Ae7i`mEic{OPijhWVMjK+(yzr&HuLnp*rfXc%+?Qo%hf&eLP@E z0m>Il%woHCJ|=QhPV|i_wvs-9b@A1=h!Q765MXl(5HER)>JvEmE@yA<`0MkrrW2tv zfLE2qIB47Pn=K{!*zA>?wzWm?O-04HNo6Zj(A2pTBDIr+g@gX|gH2-E&l!gV_c#Jj zf!GY47Obav_+wdnXg%Eixk!5 zw^bR7l-yy?MoI5DVhtc>GU^FBPJGslPedOnI;DyBzCD5w@-zag*`&n6HD6{#;JMu2 z^oE%8cBnYDG42FixP!y+cuOQvZ+DF9qjI{DbbA};Ws_9Lb0Ll`N!7?*-X*=l#kAyS z1qjnti3`h4f&p-$>w6*PZr^Mm|Nk}G%%(4;`^uf{Ls_M!T|x|Wnd>l%)qo zr#ik5zA+Mt&QF0X-Av}zCtQQxVGYvm|9swopHAG3Y`sgVTe>_-bkCe#+A$@muj{=7 zrJ%lc=}(6r-Y9s(6zYv+Th>JeU&g02z*asVNDS~7;$Xc7ZR=PG_<{i;6Jf_mHqZf} z@AwK9X5L+-4!$HVUSP-rtw#rWQG$C3pZ@Y-|3i2{ltAoRQSk@jZ;K(pc^o`kbTKB& z%)XU@#h}DcJ!K7MSEa4R@Db)MFV=Q^HtdCxw-BuI;e@8qm@~=8^1MnR;%KaDyjtrK zDxu<~;aeMAhhlGg#z0s`FWIT$uB2PxjN1u+7aVAbFs6f{Q28S6N5FCZ8~2igv#W@7 zh$#gajV7201dx1BN;@Fjy^DM$wK)lDW|P}Jz+}0dVP{1PZr>fiA~%F5iI>rOVJwY2 zdS9O2Q`BZIQBD7uhqGXFDKJjM3Y+JqK47=OB>=)?T_usdgqT;oVVJ;L3uBdyV+aa4tG27jdc_y zmjZxOo$f}Y0WNBm%YH??*yY_(?nRoR+!6M!KzM{6xW7iiP{Qu|0uhRkC3OD68+%E% zi|CC@J_F}u6$d`VJN5{THW1dbn&c{#a&8f_{aPP+SVJG&uK#k1345~igS^h}xy=33 z`Ar(GWtU_~YTp71vxH_|wGH$B_#Y7j@8C18H%YVDIA>NVz~amBP8s#dV-^;}SHh&= z$w~@%d_(zgY!H?1*wF@rNvFCp)vKY_ictVP_ zmpR$fl61{C0^DP;+Z*pm+ToshDR7&iL1TH!SqCxJ^nB7GSnO(mg#aJq;B z839{VB&p^^L7~~{dH0lepPzTd+zj*apt+x0h4g&**u0o9HKT+lNnQ#@<#rhGdx^cN z&9RIV!hvZOkN_2UnQ$Aazu6L&`Bh(@m76+iaGqPk9v=+{Se^cNHWc;vIIj@Zb9cV9 zunY^7!kDGJW~fBC#&oqX{y%h_IIV!C13fo2QD*NuU>U>#l5W7V?fyW|{#sRjl(bcIME1;Mtg--D z;uF_Sjw<^{Y{|f$p4Zl?c3ycIz{*WlxYQK`KG?cAn8>ly;t6ikm$CfX>*KYy=5#pp z9&HE&?tjs8t|G+Qk;uKD>*019xxa!LG2^y}6z_4)?pE(y*(NEZBq%s|A)0X@R--6V zpB&}WLfTA6JPQQxfSo1}AdT$BQkEhk-cx}BLb7_jJ8zOa*rR6zS;%Q4>ByjXbO++L z>!X~QUz3@Gi89cYo`bnWxu9WkQKAhRrI5iKa!+^Xaof$W*XF(BNE{YSDV0RXx3lcK z$EEohKiBU;#xA*h?~;tdWt^}eF7S!7Xg8u%$P`8Or3rc2FBW6l9bz~=667vW{i--zbpV>y?Yo!7eP$W+u1c`3_1b~$f z8=KLWsd4=5c&JXsfJYPH0e%VjL>^s%oF9G;ieV4BzmGL{=S2B1aRL6qSE2bJ0|Nue zaL}|R@MdmGAY6h#lToEqghAT!heO>~jtC#(>(C{cU-yNoh+p6t;N>s-r)5k`rdjs? z0a@-k#I;=^%LE)X@XSei+uIa@>3s&DnVPiF;XDVznY7RJ7z&V5_Z?jpR<>FXWe<_*De!jXlKI zNmLH}7tmU-^&>J0v$gJs!cXr{-;_px-hT071RHJvR$%~!W*b$PSp6lPz#k1N_G3f2 z@vvn9ShERdP>_58J5^>nFI;?N^gMt@DMhOs-DcCWQ;?&n_C(QatAeAmSijoU5QEqI z4};*FtOt*$c{!D#4B80ywIDbr1X>6h`$()CAPWax{?So+Ks;^fqb8V(YGl?A2VOAM z6&K8yiE9bC1Sf1lA>x}2iUJTN2b&;uNj;0tzYT-L{G1Pa+mq5I$Hz3y@FVO$E_Kld zj(2YK^HlNeS?52d1w4Y&F+r|%;a$=1n-9(c{M6Jy6_-TTp)vU)k`J(+@VnN2Kfpj@ z0z7Ov6F(gH?M`?xGbgqgI0f|I;4d1$(}KynxAnFb;)~za_YNq~ji@B_W-+1`XGH3$ zvc=7|QJTYnL+3+ew#{F1l1WuKRpGWBLY#2ksOt*}lPDC?I`SvN)iksto}=Q-^|Evu zYamJp8ZUih8i;DBsyjX2FGc1zUi5WcN9`-SV*sS#A(?xiZlFmgZwOJYh`HVwLozGW zff8!|*A(m53)c)piuHj)JXK$O^abZlAWs(x?8V=B^T9R!_Tjg1rUPDGn+T;&M0RE~ zbduwm9!)#JmWEB&Wh%6Y;TjPjr5SqkCp~!ji^9e++=nf1l&y(RSwmRz$nBqrsrj|$ zR71+s(}iuGd0%W6&`%bqeBnmLPZ#}Hij^za3MRNoe(!4-!VNw)-vjzwrfe@eg2nq?-98T5-tg6?`HfHu&xiJU2L zD>)v)T2y@|bj4$W)Kz%lje#O}b0F5=gC{`=?{Bjv`8tP!aOuBL!M#EOcOV*GY9#2R z3iB_Gbk!L%b|;Ynj3w~s=@f~+Hh9$u|0?U64@pfUU)%sEo_j9~tTrbe@veTK($ni; z2XeOpedrXkw1Q_SPY8@kHLS(sc5 zet83V)Z)#?=bE9T&84$Bt{wc5)e%z6$fJVU9q?g z4xhfpfIh-pn6pILJ8fz6<~@~dFcE>*n+ueLH&SedMgzxrW1OD?Ij1mf;8*)|lS=++ zBIRkEgm|suU)_JTAc8(ODZ_@tN8y5;SGGTZ5DH%mpv}rm?;m8gesTr({vz7mWCY*+ za9`c_hG*XHm_GLx2sVn4EC#}eg8-h0lxywSvu_W{W}YE^q;`)0Wk#48czHJOTg{~Y z2AcoilLNrd` z7&8$Yc`j?O@AR~a4dfdtLW=*J7BU^GO`CV>@E(Bn3A8(}x8bG-2%hCxn#*=!+=&QS zumtn(%nyVM3vyvO*)V}!PWm34!~x$KNdgVmq!+}*=+|bT*B&dCeyNDwDeL=g*l z>9U_hHmNq>T|SkB5RLCzFBTqaL6?@1Q6xMda^hUc0mJ8}r&(OEf#(&Ak$^F~Uff)` z7O}BASDrn<$8VW0RzCGe*!xj9R$Az2_aJ9u-mm0H@Hf=u zc|IUNv(V$U)!oRT@Pb1V25OdE%C=t3=cYF%=(d5CfnS#^l-4DHf|g}y#jQ?>fv}wU>MyMi-@Dhq`g1wyP)LpNoa0c|=C^D!OUO=GVSa~i z#{-EYJD;0WA0+wYcDOp?p$pZdcb_K3O)NM-2L7le}w$y z0e+hY2eZ}dXJr257yW_r;q^66!;Va`^Gsr6Mg0Yruh_kTMDD%T6BhnQ2^2ikT!GE1 zxpz3$aiy?x6geL9u}>F2JX0nY;sIl3k+t=||6XaEi?S$_%4NN72hUKV85a{%ViqyM zWy@B>L%1xEe1vEV!IWsUNwW9cE?yPj5It7$Ae07b-oma;Mg=Nf=Od9t$8JvS2x$#GWzJ`;^ zk-9WQL&aJeuwJCH-PH;NGVmt<_7E0N^f^$fUD~}iwcjm>in?dH`|$9vJ@M7W*E6d|Fkqy3PoW&KCs+_0)>OsL{s-5>$VU3dvTzmmN(_1kCr4Sb-gSkuxo|b~Z zuv>QPffX2mC8UK}23b+*oI4WAqa3k7yv2EaE93EdyR6Tn5HbMfo#3}Gm= zSp?{&XuH`31YAzK?`%_u>Op@3@mSfZA4R8l*i1S<4^(UzxOt)hW(+089oA9xY6I?3 z5LdHPsa#Pfmr}oQ*Ukm`{0nZrRv>hySypL{_vg;%0pcE&uN(5_;lb|su8G9pRVM6K zGe+&@Asr2ODkB{G+_zk&BGKPm!vNVURf=$y_}4gyrIw z(b7XZLK33#-=-MgEqm^F{xWl&tf7J!45}x09Hs%#Z$Gt>8dywP&W|riKae;nAsh8 zf)bps>85lPO;b&1`Oke@y8ALJ!7y7j_o?ik&BbOvbkv3{#wwcPxnOG0Q94GWjIdMw z^83%8c&R^JZ!f!%A5{a&-)J57eZ8nv6)R_+jR5EdB~euz$bhjj;L2FpZMoYqpi=;p zUF7()x@S*rbch)ZZNTwy^Yiq~_bBEmWUJ16)130k$`;#sYiv}(4~cf}XDSWvQGjcV zcLmX!(pQr=3^QRf9>Ev-ceLt|&xZnDuVj~ycX%Ykl-IMyynTeYFCVmtV3+$8Nxyg% zU3AWZoJNaVX19PcyaW$_U2_&mwku|NL%D4*FTSJV8AK%r@KlO`I7b+w12yf73rVgI{7Js zZ!h#QEOup7p`(obB)ezt9-3QyvTSk+CU{bo>`_p$-HeKVcFYfVvUz+mZLxakf$rv{ zvqvs<>F!GA@>-LFJG_B*+Q4M(uF|pOCqSzbFi)O_R6e;e7??(5>m(ci5y$Q4k@0o+N2ZN4LliUkJE9 zT~FN?f3@d00PRSyl``V-=mx_iMd+#tbeE^*Cj_3x zxLcI&7t6IKaXn`g5^2JGSgOKLZBkNA+kXklKngYDz=zU+H~g(Ma1#Io<;YMPxYvL+ znZwDftMiwdg;h(i`1xYILj+CgrTf!2U%3RukQ$%=T|!BpNHX(O#C!wYV*E$lrpleo zr2yjScB{DsQyBh~T7S(NZ?MhX6tY7f0!+_7!_D#^7^VgsO8~NYtd5oZhl{jJ9t7%j z7v3AOtI*hZM~O%(g+>so7+xoPovQ4~)S}B<%^B8CR*d<@+oWyfcoRqQ3xXE`FJ7#t zw0}VT*)z^!kUW>$z4K$;vLkf6S`uBp$GYy=C+TJ{s77^>IK5S&q`D1um>JGMS(64- zL+92qr4V2>tub;}rWhY%@lEh!K@DO_$2Eg)0>SbijbFWsf9TTqSGsfwUw&ep z_ZYEAFOS8?d#fBC)^RDau^NNSuY~DvTA*(AjQ_i&2RTOegrdHef^_}ZT+RQ5bw~M4 z9OWFtdm@fEfJ!i+kOdH|o7)m@fAxL}zFTXGge7-I4es2)&m5#>{67Osx?Cb2GQuQ__b=AFWV{ey=ZOQBth&UJ z+HYMmhRmteWW*6Mbwnp;O;^(tq7?|J!D(j;X|}to5BB`_d%%fU0Sj`(V-2pceLy(4 z?_86Iu{Lnbj^chhdX!?o=-U1tf#K8+e9A0Tfv&-138YZm--0(?45JiPn&o-63VE^#enbU9TUI#MU<;@J1ZaNEm+H% ziqdo89jN2o>wcww2qZW9#LNH#=;-R|H=$T(WMn_U&DS*L#;%J0wPwi>+=Jm*2>@E} z+jCxB(LgDp;o{_&2+{A){KaW1bUBTc68Q}Y5@~7a)|we*Hfck|5ZyRVK>3Zrq|%Zp z2Y?7A2)sbq*re}wq1Tz&{u+I%KJ&D&2@zuC`I|yZz-fwA{bv9mBO1| z=Jfc-2KJ#tZp_`T5vQ@JCA9G(pydRUeh*W(5tquQd{Zx3;xeY`cS~Q@&EkJ&RkQ~9 zT=GtY%F6x5njQQzl9I|DSo*D;piEDmzW!CpHv`!|kY-w!T5!2&5q+AAzX#>6KwAO3 zOlj!bnKOiORg9#sPs|L}U0k}d5C^!OMw?llXw}&*tM7OmLQY+C?AH71zb*{Cv7Bl4 zECS4e|GUbs4&kVa76~Fav*p3OA?*CYb*Fk z6QIRUa_z-?Z%7ZBY}@O$H-#1~QxjTXhfyc-yFY>#CGc>=GO5{Ly=ytLTL17`*>M3oRHUF@N=-;UE4`XyVIc(&E-QoHv3pJC))~5x*x7xO= zo#!k#^-L4b;DtwLGN(0|d&Y&j*0uuiSZG8591L(Dy|h-4J{f$0VB*dgz*t*moYnF+ z&*zWr{#&uM$$CFRv2PE^>~%TSX?mlNr|p(nS*ytt;?_|bIafx(K7i#C ztQrBNT$BZWhg|+N)Cm|EpoIOMUcVH>Ae~GgMH4}h+!1qmwut`TMEqjzo#1D_zB2z5 z0b6+Pvb=r&QY{o{3u*`3Q+S7(AlL&&EZq7PGh)E~U6tk~Wdj8<}?E=JIBnEyG77pW61svq~*$ z7z1cN`@Z?oHz%$FItx~wTxOYJb|H8*Bz_V(RP1+gBVu$f+f;c`K*P4Fj9(q@dh z{a&I{YApuD32^Lv#K`H0tf^m;-3w0iNq-sy(D{)3ADg+CBI^3HhRZ!<$ zK*BfpNBv=)=5IEbkV9>@J&nlk&-~6+`yuRMBkQ&Aj}lG}(4|qGb$hEbg$Bv;gq!_r z_*ghmm+cWbGCMn+p`VCzKKzVz5Os~rvqcTOns9qKN5bwSf^)T*+Aemj_7{GvKPcanzNj5!Vpqb{(9alq(x~6h{tQ_H z`ZG&kEA4e$!;oDhZd@eGVod}{Bdhj~Wi(sj6F}GxRW1(%Zm@8LRqzW2mR; z9}y+c`SLRXLKkOCC7m7MKVLPo_mK{~eyNn`rtY$HDP3PLbs|$AN3qCU;+2>-r$8jPg%Ul*&kSaL4iVAgblH5gUt*$4|S=zaFt&N}{6S38rMZ+nu3+uU?`&XA4N?~a?))%mBCK-f^{ z*}k*hqRctizube`y@dU|KjLGeyUKocicN$*;~V{ZTf=B8BHe39`_0^Hl$hnrkvP?- zA839K^{9ThXEJBomRbXpHZ|@3XdWhsHh`#_LWWHA59?WmLLJdv;B!0asNE5IzT1F5 z22qDovPa8=)*>dBeIFXLP{v&hT6OeDm~{7faVdQ)fRZv7F0X zKp0*TUXB+WEA&EG{{Hi~oFhRwD}@jCV|7(qBt2TUJ2@O;1EgLWK`@#XtVczNjKVJfI61Uw#)jRPOtwAp_M@B=>4-JI^Ok_s@~^w8jdma#{!8f z#@ptnc)qwb44iq-cJf59hnyl`v?S$iTLJ6%(v`5yXE;4yb+=xRkMuVN{Tc9XT$Cw@ zYHoV1Z}@p5{m-!kO_@nMT%M{gk)O?lVMLqbrf1BxJkt0Bg_F8Xyf5+bO~59Kem$Lh zwQ3lVz@?yQTEXF-0lW*fe{k$p4MsAp;<(|SfIawXpt?3Ult3QK1xlWvBuZRG$GQJE zVI2*kSn;JoVRO)*xzd8Lso{TDQbekvW0RkuD=vYX13LVzKV8RvoW&OY+5+j%m+xh< zO`xS@O&fcRxhaR&lzm*!@TD=9I=W+}MaR4bFC~;Rz$#|{=?j6c3Amn=G2mL#1!4t77 z@^V6cX(tQOw^Rjr30Mr`IbXZw{$Voco$x+MthBVEf)$Ysmo|HQ)kCy9;alGOo54H-dnX3C41As5UU^@B zZFSuQG)x(uB(FHc74iRg49cKVYenk}=aDwQ`?00hRLzEZ9|%&X=7W^LRc=fihF?%Z zaRqA|!yh=v@_mF{L>V0##17DHOg+0G{lT835#LH-S6_=zYb8150f`tfhVRN7lsjN$c&h!vm^%9X3@SI9yspvN)XT zR2elHq+~Vwp4OM|Ik{POhE<-TYK_t_d#dM8O!||? zw82<&)V43(!t@MDo`=kg__k|!Ymp<9UCLwXbp-9zIv94~`|5U@`mE?di|*o5Z=g%H z{-<3wfZ4!ZkxxzMfuQRnAaOt`Ob5owxvE76itzWIFwbyHKuISt((OF{-Dq^PwVQ%9 z_}#shSxOn_{kX6j$jzQ6!AsG04$oK`9T|#2$Jx=5j`8ohqf=X?Vtc=ihp}zSEtRLM zT7}N>D!se%ITWrnr%^d@0m>!eslJ~T&-eC^eq`vlH{tV8qK*-ag1_esn@#kHL+*ro zUEPiU8?+`;|FyZO=>y=CHIz%Fp6Sh}zWBeYodV-uZQOq`$cEiDI_C~P?g+9PQurSxOAR@<7L^@pgEzE+EE#(&cruQR&UdAe_hIrMXd&k)RkEKF~)=ln2;MH)^EW3Pyz`XlHsx6{`eua z#>09u;L^EB8w*+S0ScWUb_Xu~55c8dKb~d6R@8eL?JSUlZvLvn2{QnTvP8*ei3d9` z@tt%n&?qzyUb=t6CsT~3@2n>e_YQ#MC5E$ikM8K`{?V{aF8f)RQhJ_>o5Nuf7sPrT z(pJw!97B2cq{W2)%Yj(0YUlyb9fci<3u|as0-9rhwF&r=qIjug4vIYN(b81P#O*QB zxHKUx1M9mWUe_oL)sZk5=rEho$k%dT68g=&)#}=X3v?F^CvrKfj4-)1`SDM^uWphQ z=U2mI{=#ee^L9eVVsvJ??gK+Un9n!{6;0^V0A8)YNtW)QE|Kfj!?dm#LsomfHkc7i zo9NAF^Z^5V_KvhsozTzAg^8-Y`(VpLsS-6D_Y&yr1o*MZ-O_K)v%pn;mHzRwAEAse z=;-g?_p7UtJ87(p(s;?pr!G)!WCM3JQ5#ZV;CEu$J@!im@23p!2if$;1n73)TWFU6 z+48}Paq=T-s)||i3eUzsk`u;t;n|*M`J*rG&xh++rdD3-zoqVVmV`*zP@q^WR0CDR zv=c_`mcW`9<`r18!u58I1^-2xfBdQH(BAE9W;OB$lWZ{cfPsPj(ZwV+|9K_Rcm_FD zb>{Awe|-wuUPHmc4ra2h3X7@oLCfV*yWio(;5Y-N&}!8o{lq>H$=~v1X~mrwiy-*4 zFpS?DeCS;?Yrc|X6iivsOSHkUv|h0spOxycESe|CO%R`}X(^nW`QxMO`%QBIwOt*M z`So1o^mN)NY5N@l4;wE0x?C-A8SRuu{aN^>_2%Ms0~!0Vk*N{fqsFOqXZyUHwgZ1e z$25U>;zZx+RlD4TBZ%{Zp|Wf{&+N~;gXf|;Ihpl!#x*%)UzJ)-gEzCeKAj7R*GW2B zqy*62p>Pu({)|;}s|Gs)6j)OxAy6{@tnd5%horx+rHqsH#nngB!I>^L=5BEZ(-OxR z>9^FuyXC=kCYgc{4Z10Xjz7)8oJri%B>m|}8utT7zg)90}Q#gNg8Zsw)txIP7k`bx28pE&|NFTmrvgf_8jcnT~?otOwDX1$JG_4z9ZJAC)?2$gFbsa zXj9RF!@5&gsGB7dzn4GQ<@#X+$f5xcd|?2d(x5^J-4(Wsm_F~mWWR(b5gfVC9dKUQ zz7>G)xkbHGu$VbX#mBFAx!BLIivR%+EHy2$i~{K&BzP#_=!fu10zZf-!ihl*32d2Y zD?CkWqD*3^F6ACIdrB}iL-A66MLaD55C^jc}gd@mhHIAG~F_=FcjmrbFtA3y3h%* z)0lLs2COI+xA@_E9%mOj=k5`!Yp?fS8->}mT>a|e#KsLi*bz=>p{}@`E%syf5p&jW zDB$0*9+{mLN#N8~w^DGvI5IZgnR#~d{i#W^mWJefEo3hf|0z#2C_g(KGkxEE!q9CA zx-1H<+fx`Q_pg4#qOdVp$(JLuIBFBIIj|BNui?=7Ksw`1N9=gnq3v0r$LS`Baf*xw7AiJ{$kZh2USY^n;P=ADYX zR}haG`up;gJ=QaAB$IoYZE6#IZ`_|%zxqaRqD)u1o)%WTC-PK4DCum>MzF{KzI?zo z_?A=Em5dT6=CAu9kJ+xgAQ@oUxvkCsd#QM}yX`i)T!M7aQryZt!c|9$egDiptas&C zdJ$`YT>&pcuBv*QEv}&3N(Z~`-rkxSBw<7sufDwaVtVSCPP+l;!Oxbnjh^EAlkVL5 z`1L56=~uU0t~%2U@#08oG}ZC*Xn$t))$T3ER~I%V{{zTFT1|#wD%-#?dI1Y<HP{66|eC}`II*3}sg=(d=!oJiB?R)FqDxD(uZj(`0+ zo4p{o@N`9UV~)wG1qPDt?-Rs$I^`u(U#Hx+kN8TTR)EJc#qFIl0nrQ3;LzdW1en-J zxXm18GT%*g91Wnd7x)hOjGWv)wMHG|TzcB51(XOffwWYz%BVh~PfF&b(9UI}fMl)e zxv2EhDa$<}j-m`J2F(uik+7iWzitQv<1XK9%uW4f_lxD3V)qUppHj8IorrWAk%FGS z{qpj9d#)2VEVL^uP>AxN$i+^%UrsF8+Lw6(-vI+6|@34R0R*NzSTl|XYxdnFmzqLE@q;> z;vNh|=ib$(TEqUYs`HL&Vht8Jh{zQb1Sv}IlF&gQh!jIj=vA8Z-jps?QRzK&LX{8* z2wqBnP_G~*^xi@zfPjc}gMbh5p7-wi_dDP2*_oZ4`OWUm3`x-QjJmj0r)B#Ot*`m7 zDu8-GUP}=&wK`xFAs_sIi`BI!k`<}LWwW0$ZYZ?A?hBKE3Hw0W)Gw!F6>uSf=Bd?V zK;-9?3ylw907vU!^lCfvFaz|!n{vUB-?fH0ze zxVz&&H)#!Oc*B9EG#)?dhy5gKmSOZDo2VWSK^0Up#w2$hgw4~vQpV-M zbH{l>t`p$|3}&f+udZq_A{Y>|MZH14z#5YvYk1z?5&su|#K)@OfaP+w5T)Q__{nbD zE&bN-pB>pwPflL#C4OsJhY=nh!xLkMf>%F<*yFHXXezj_QoB9%ciHNL1 zl5h!g65_Igwb}ABeP;e}2Gd85bcFVmB{F`C7egJdepzk63MrC3m-pm<;Gb$qlFkJ| zMv`<1VuYf6C0sY7-i?11_fh(#D!TD&(6mW zZEreL*3ydI#5ac$&Chqi#)Q6!x1XU(P!0N-XYnWG@|1OxAfi& zI(-ibq(pb#AH|#}!>JZ{Q-QSPCHWVLbyZEqApxtY4r$=ocdq~gHl2L;$!X3qCWE!S z1!B>+Nuvtgr_d1ptYE@m-4M@MbMm#O6#d{c{Lk$%NzGr23&(unQrI^Xi@!RwgYBn! zw|N8@TI*cV?kFSAgLYd>I;w>>`DAL}^KsbASbA$+U*3tk12^g`TYdN}jnpv{nG*l1 znajWRrz6DprNr|Uf<(2u@g+O%k`b)&iI=`ZFkypw-_ls#X)~5(L==d$pwFFx_8-A+#+}w#!Qgjz+L0q<`a_LPH{%s^L&|KXK%(?ky zQSDBC%^BLP&$tP&c6I*FH!_c!m)pnVHV6o#n9lYuJ;P=x`VzuUp9?LS>iu~v`-QNh zL2}v1onlVjc|%O-5Y}^Kf`ua%2YIgA8kKfj__7M$uS#D$frAP2Bby_JB0m!SD>UW& zOYU3kd~q#Lg9r;5^%hLp;v({){Vr z+t%}p!bXS5pF18nh5r~Z5^O=l4iwSpM+9Fv<8l@g%yQHQAw6j!%c9lyWM#Xg_EWV$ zu|bvbbgk!)GqaRDHXSRB0W%A0psP!x=|O)DggL&wDML6Gr+{_noku+)c<)6wiWxT} z0xYEXMNd972JXFGC-dtE4$f7ihP@w$3E#6=XbifTNQoU{boShtp1l1wEjDHBqoz4~R<&z) z`tt3!`rP?M%)+; z(B9*2ELPNHc#{mGryE$$&SqxKqd3u3XS}(q@KiiQ^ zB>F=aToqM{K=N?Cz?IIrDwz!7k8NIF9)6Ad`ZsPw`k7ybquDD*a$nU{hO!Jq1Dw1o zjEU`m2X$Ve}&x}Hjl zziAFXHFc{)eoZmW117O#HM=>Z8?y5YRMF_?^e7bd3v#9N!6pUejbXO7#k zCAhALVB!ptE6VajNcbg%Vld{uXWj0$ZPFiY=H+yWCMnHg2L5btw!4@$WA5vnIX+b1 zkxJxsosBK9RFDUNybyd>)d+U?vY2GPOsCu8Y98P|w*E-wB_%n(c1ns(kLTfkejs`U z2lUSFIL9nu4sr|EUwCTKjcp9kwHt?#PzxjTEM~<&*~nl5NrF2HbUak|YF8bM_zW&M z&!jA{{U>nAcoeNHEzII7dgl+bF;9DQXVfsPuV3n%=wG66NbdL$OS(W zaYOLG2&j78CRJ+Wigp?QB&9|2g77cNQ7(MXdr`fKPy07`+J>sd9qsu45~_ejP$oV$%4YX0_P;FJ7qq}K z8LVDDyFK*(cJIj2kUqf&h_dF~czRXfoMeI@4m&a2aIlq+S^$kaw=?GFlitriv? zc-I(xD09r)`49d|2Y(;jI?E~cIXbMm5++AB$OwSu9MEM7d(3qRT%oUnqzlB;VQ%P7j4Vyu2Hmv6do<`^5>W^`(M30J% z%5&vkg+i8)n(&y;_gA_tXM_p+YiVlrDeNqI&(~jkQ*ZKjs}U$)G$J0RMp!vGI=*Eu zSPhnw2Z1u3821(KT4>m)wAYvDI7MP*5ea=Z|ubL z4zr;ErF?)<+}nKJ{)LtWSNAt_f=2f!OwWZp5ncN(rEf+$a`3wKKh$4<$zM$%eJhqw z=SS=}d3emg!_Ef}HmFsTd4qax6oVLWHsx^u&IBb|y@t+cojGohvUFX~8c3#Y5noOV z*WPebhhJCvVD~|SPG0me0D&S0+PX+nch|Y6Xu8EsN|wvsCnXN|j;76s5~_0V8;tfs z8PABYzxfAlS>gb6Lg0aEP?Q0}LKXdmp1jM-9*bb}gvbt2w2P1{q7b_TH%XIiP`cPwy{FGg|2J(!{1ANkUe|BL@Cj@}(X|e!`XG0!} zbdVMay)d?EKcUT^)_3&2r6zagKB{$NJ>~O+W(75V5^O*^(Hq`hbJ)9IdA~QohMqiJ z#9$)arO>#bwd3L`;!brKR1r{FNZ*AB?+sO)LLgAHbSUdiyDH2u(ry&1?B9`q#e|8W{KT#;B-D z>0Ng*IxSV8?%@W~C04bU1z4ch_onZSDKJr{#&`&o7$^zJJk%NKLLhean}Xydo~mV} zFpaKp1aTe7l^X+tq$wF^#SH+Sr?aWGQP zP~fg^DrM?sKNPLC01Uvtf3l!PCUi$LT1<4bl+KolF06Yr;)TcopUKiRasmBtOvTOt zl&99OL^tx+bds>jo=%>@bTxmj*L!x4ZZjS_sBo8oZ|0B2ozX8OuVj^IaaHc0jn zAHF*s;aL?*s#*gAWtDv8rW_K2C_eB4-f zK^^dliw?0pVcui!8>_sJQ9CRVY=09+OGAMSWbV%emWs>Tk6jC&7$bLvW`q0FRwpz&v>w7GeaF;Kc4LC zBBEX|QfcT~MQt5Dnb-jOAUevS_WiTUgaS%A^$BfLI46@D2EMOX3}7`h2J0dptKf`a zEVmaupd^&jtcy05>W1vkekZkO+r9pyr5ZcY)0fxu4W@?;M=Hd%Ry8 zM1!G+p_~Op_!Oq_6o?ATmYs4Ae>xH?l3gB%>?Cy_SL)K;8FhO?4SY){`Fc*^Fy4j1 zVnB)|<$+Dnz9GsSznmlQu#UYo7+W4b=IKtsaR;+NT@LQJ30GBM^Q1x4j{0%6c79 zB(d8O@JY4M7==c5auk@8wK*W6xR-PH9y8yAliig3iO1DZDl6>C*t29sK9{xk+muwa zd=)MOCtyFiSl>c%9h>irLkf(oCbX=NT01BeZj9BkC~Y`8 zpuTfW-FjY{s?zhA2FXnZ!6{Qq$T~B)%MHvVp2d~1Hk6J`?{8pa gEOqE5S^Gs+_fEwhq4=`>GBqNCC~GNIg00^C4=PJ$vj6}9 diff --git a/images/schedule2.png b/images/schedule2.png deleted file mode 100644 index f26b87247c506f7b5d3ba98a94deed277b182359..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12936 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 Tmgm5+NFXKoXL3cdW`F%30@jH? diff --git a/images/syno_hdd_db.png b/images/syno_hdd_db.png deleted file mode 100644 index 451795c95c2f472050ced54e0f99b9829d878128..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23731 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 diff --git a/images/syno_hdd_db2.png b/images/syno_hdd_db2.png deleted file mode 100644 index 75834bf1c55c1a9dfb5473ccffe95fe4b6134a3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10601 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 J^7fM#{|hDlv+)1` From 7f0ed23cd69e4e19ce0fb7b9d84eae54c21e64d0 Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:01:10 +1100 Subject: [PATCH 22/24] Delete README.md --- README.md | 59 ------------------------------------------------------- 1 file changed, 59 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index ba0eb2e..0000000 --- a/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# Synology HDD db - - - - -### Description - -Add your HDD, SSD and M.2 drives to your Synology's compatible drive database. - -The script works in DSM 7 and DSM 6. - -#### What the script does: - -* Gets the Synology NAS model and DSM version (so it knows which db files to edit). -* Gets a list of the HDD, SSD and NVMe drives installed in your Synology NAS. -* Gets each drive's model number and firmware version. -* Backs up the database file if there is no backup already. -* Checks if each drive is already in the Synology's compatible-drive database. -* Adds any missing drives to the Synology's compatible-drive database. - -**Planned updates:** -* Detect any connected expansion units and get the model(s) and edit the correct expansion unit db files. - * Or add support for users to specify their expansion unit model(s) as arguments. - * Or maybe use the shotgun approach and update all expansion unit db files. -* Add support for SAS drives? Are SAS drives listed as /dev/sata# or /dev/sas# ? - -### When to run the script - -DSM updates wil almost certainly overwrite the drive-compatibility database files so you may need to run the script after every DSM update. You would also have to re-run the script after DSM downloads a newer version of the drive-compatibility database, which can happen between DSM updates. The best option is to run the script every time the Synology boots, and the best way to do that is to setup a scheduled task to run the the script at boot-up. - -### Scheduling the script in Synology's Task Scheduler - -See How to schedule a script in Synology Task Manager - -### Running the script via SSH - -You run the script in a shell with sudo or as root. - -```YAML -sudo /path-to-script/syno_hdd_db.sh -``` - -**Note:** Replace /path-to-script/ with the actual path to the script on your Synology. - -

- -If you run the script with the -showedits flag it will show you the changes it made to the Synology's compatible-drive database. Obviously this is only useful if you run the script in a shell. - -```YAML -sudo /path-to-script/syno_hdd_db.sh -showedits -``` - -**Note:** Replace /path-to-script/ with the actual path to the script on your Synology. - -

- -**Credits** - -The idea for this script came from a comment made by Empyrealist on the Synology subreddit. From 8a9e798601ef28e62dd68cd4428f3529d60da2ab Mon Sep 17 00:00:00 2001 From: 007revad <39733752+007revad@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:01:34 +1100 Subject: [PATCH 23/24] Delete how_to_schedule.md --- how_to_schedule.md | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 how_to_schedule.md diff --git a/how_to_schedule.md b/how_to_schedule.md deleted file mode 100644 index 6db03aa..0000000 --- a/how_to_schedule.md +++ /dev/null @@ -1,25 +0,0 @@ -# How to schedule a script in Synology Task Manager - -To schedule a script to run on your Synology at boot-up or shut-down follow these steps: - -**Note:** You can setup a schedule task and leave it disabled, so it only runs when you select the task in the Task Scheduler and click on the Run button. - -1. Go to **Control Panel** > **Task Scheduler** > click **Create** > and select **Triggered Task**. -2. Select **User-defined script**. -3. Enter a task name. -4. Select **root** as the user (The script needs to run as root). -5. Select **Boot-up** as the event that triggers the task. -6. Leave **Enable** ticked. -7. Click **Task Settings**. -8. Optionally you can tick **Send run details by email** and **Send run details only when the script terminates abnormally** then enter your email address. -9. In the box under **User-defined script** type the path to the script. - - e.g. If you saved the script to a shared folder on volume1 called "scripts" you'd type: **/volume1/scripts/syno_hdd_db.sh** -11. Click **OK** to save the settings. - -Here's some screenshots showing what needs to set: - -

- -

- -

From 72c582a3deeabcebc3c47767106189744bb78e95 Mon Sep 17 00:00:00 2001 From: Dave Russell <39733752+007revad@users.noreply.github.com> Date: Thu, 13 Aug 2026 11:04:42 +1000 Subject: [PATCH 24/24] Update README with drive compatibility information Added compatibility table for 2025 and later Synology models. --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index ac30533..44a31a3 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,18 @@ #### What the script does: * Checks if there is a newer version of this script and offers to download it for you. * The new version available messages time out so they don't prevent the script running if it is scheduled to run unattended. +### 2025 plus series and later models + +The table below summarizes drive compatibility by product series and drive type for models released in 2025 and later: + +**All series (DSM 7.3 or later) with Synology HDD DB:** + +| Drive Types | On Compatibility List | Not Listed | On Incompatibility List | +|---|---|---|---| +| HDD | ✓ Supported for:
• New installation and storage pool creation
• Migration from existing Synology systems | ✓ Supported for:
• Migration from existing Synology systems

✓ Supported for:
• New installation and storage pool creation
• Cache creation | ✓ Supported for:
• New installation and storage pool creation
• Cache creation
• Migration from existing Synology systems | +| 2.5" SATA/SAS SSD | ✓ Supported for:
• New installation and storage pool creation
• Cache creation
• Migration from existing Synology systems | ✓ Supported for:
• Migration from existing Synology systems

✓ Supported for:
• New installation and storage pool creation
• Cache creation | ✓ Supported for:
• New installation and storage pool creation
• Cache creation
• Migration from existing Synology systems | +| M.2 NVMe SSD | ✓ Supported for:
• Storage pool creation
• Cache creation
• Migration from existing Synology systems | ✓ Supported for:
• Migration from existing Synology systems

✓ Supported for:
• Storage pool creation
• Cache creation | ✓ Supported for:
• Storage pool creation
• Cache creation
• Migration from existing Synology systems | + ### Download the script 1. Download the latest version _Source code (zip)_ from https://github.com/007revad/Synology_HDD_db/releases @@ -88,10 +100,13 @@ ### Options when running the script ```YAML -s, --showedits Show edits made to _host db and db.new file(s) -n, --noupdate Prevent DSM updating the compatible drive databases + Always use this option unless you need to update + firmware on Synology drives -r, --ram Disable memory compatibility checking (DSM 7.x only) and sets max memory to the amount of installed memory -f, --force Force DSM to not check drive compatibility Do not use this option unless absolutely needed + Do not use this option with DSM 7.4 -i, --incompatible Change incompatible drives to supported Do not use this option unless absolutely needed -w, --wdda Disable WD Device Analytics to prevent DSM showing