diff --git a/Birders_Guide_Installer.sh b/Birders_Guide_Installer.sh index 44065a0..b5b1695 100755 --- a/Birders_Guide_Installer.sh +++ b/Birders_Guide_Installer.sh @@ -116,8 +116,13 @@ stage_2() { echo "Follow the instructions to fill out the LATITUDE and LONGITUDE variables and set the passwords for the live audio stream. Save the file after editing and then close the Mouse Pad editing window to continue." - mousepad ${my_dir}/Birders_Guide_Installer_Configuration.txt &> /dev/null - while pgrep mouse &> /dev/null;do + if ( env | grep SSH_CONNECTION &> /dev/null );then + editor=nano + else + editor=mousepad + fi + $editor ${my_dir}/Birders_Guide_Installer_Configuration.txt &> /dev/null + while pgrep $editor &> /dev/null;do sleep 1 done source ${my_dir}/Birders_Guide_Installer_Configuration.txt || exit 1 diff --git a/scripts/birdnet_analysis.sh b/scripts/birdnet_analysis.sh index a7cc326..0e99b0d 100755 --- a/scripts/birdnet_analysis.sh +++ b/scripts/birdnet_analysis.sh @@ -5,6 +5,7 @@ source /etc/birdnet/birdnet.conf # Document this run's birdnet.conf settings # Make a temporary file to compare the current birdnet.conf with # the birdnet.conf as it was the last time this script was called +my_dir=$(realpath $(dirname $0)) make_thisrun() { sleep .4 awk '!/#/ && !/^$/ {print}' /etc/birdnet/birdnet.conf \ @@ -76,6 +77,7 @@ run_analysis() { cd ${HOME}/BirdNET-Lite || exit 1 for i in "${files[@]}";do + echo "${1}/${i}" > ./analyzing_now.txt [ -z ${RECORDING_LENGTH} ] && RECORDING_LENGTH=12 [ ${RECORDING_LENGTH} == "60" ] && RECORDING_LENGTH=01:00 FILE_LENGTH="$(ffmpeg -i ${1}/${i} 2>&1 | awk -F. '/Duration/ {print $1}' | cut -d':' -f3-4)" @@ -150,6 +152,8 @@ run_birdnet() { run_analysis "${1}" } +date + if [ $(find ${RECS_DIR} -maxdepth 1 -name '*wav' | wc -l) -gt 0 ];then run_birdnet "${RECS_DIR}" fi diff --git a/scripts/birdnet_stats.sh b/scripts/birdnet_stats.sh index c666597..b267f88 100755 --- a/scripts/birdnet_stats.sh +++ b/scripts/birdnet_stats.sh @@ -1,11 +1,13 @@ #!/usr/bin/env bash # BirdNET Stats Page -trap 'setterm --cursor on' EXIT +trap 'setterm --cursor on && exit' EXIT +trap 'rm -f "${TMP_FILE}" && exit' EXIT source /etc/birdnet/birdnet.conf setterm --cursor off +TMP_FILE="$(mktemp)" while true;do -cat << "EOF" + cat << "EOF" .+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+. ( _ ____ __ _ ) ) |_)o.__||\ ||_ |__(_ __|_ _ ._ _ |_) _ ._ _ .__|_ ( @@ -13,37 +15,79 @@ cat << "EOF" ) / | ( "+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+" EOF -if [ "$(find ${EXTRACTED} -name '*.wav' | wc -l)" -ge 1 ];then - a=$( find "${EXTRACTED}" -name '*.wav' \ - | awk -F "/" '{print $NF}' \ - | cut -d'-' -f1 \ - | sort -n \ - | tail -n1 ) -else - a=0 -fi -echo -if [ "${a}" -ge "1" ];then - SOFAR=$(($(wc -l ${IDFILE}| cut -d' ' -f1)/2)) -else - SOFAR=0 -fi -echo " -$a detections so far" -echo -echo " -$SOFAR species identified so far" -echo -if [ ${a} -ge 1 ];then -while read -r line;do - SPECIES="$(echo "${line}" | awk -F: '/Common Name/ {print $2}')" - SPECIES=${SPECIES// /_} - SPECIES=${SPECIES/_} - [ -z ${SPECIES} ] && continue - DETECTIONS="$(ls -1 ${EXTRACTED}/By_Date/*/${SPECIES}| wc -l)" - echo -e " | $line # of detections so far: ${DETECTIONS}\n" -done < ${IDFILE} -fi -echo -echo -n "Listening since "${INSTALL_DATE}"" -sleep 20 -clear -done + if [ "$(find ${EXTRACTED} -name '*.wav' | wc -l)" -ge 1 ] &> /dev/null;then + a=$( find "${EXTRACTED}" -name '*.wav' \ + | awk -F "/" '{print $NF}' \ + | cut -d'-' -f1 \ + | sort -n \ + | tail -n1 ) + else + a=0 + fi + echo + if [ "${a}" -ge "1" ];then + SOFAR=$(($(wc -l ${IDFILE}| cut -d' ' -f1)/2)) + else + SOFAR=0 + fi + if [ $SOFAR = 1 ];then + verbage=detection + else + verbage=detections + fi + echo " -$a $verbage so far" + echo + echo " -$SOFAR species identified so far" + echo + if [ "${SOFAR}" -ge "1" ];then + MOST_RECENT="$(find ${EXTRACTED}/By_Date/$(date +%Y-%m-%d) \ + | sort -t"%" -rk2 \ + | head -n1 \ + | cut -d'/' -f8)" + AT_TIME="$(find ${EXTRACTED}/By_Date/$(date +%Y-%m-%d) \ + | sort -t"%" -rk2 \ + | head -n1 \ + | rev \ + | cut -d'-' -f1 \ + | rev \ + | cut -d'.' -f1)" + echo " -Most recent species detection: ${MOST_RECENT//_/ } at ${AT_TIME}" + echo + fi + if [ ${a} -ge 1 ];then + while read -r line;do + + # Get species name + SPECIES="$(echo "${line}" | awk -F: '/Common Name/ {print $2}')" + SPECIES="${SPECIES// /_}" + SPECIES="$(echo ${SPECIES/_} | tr -d "'")" + [ -z ${SPECIES} ] && continue + + # Get all detection files + ALL_DETECTION_FILES="$(find ${EXTRACTED}/By_Date/*/${SPECIES} -name '*.wav')" + ALL_DETECTION_FILES="$(echo ${ALL_DETECTION_FILES[@]} | tr ' ' '\n')" + + # Parse highest confidence score + MAX_SCORE="$(echo "${ALL_DETECTION_FILES}"| awk -F% '{print $1}')" + MAX_SCORE="$(echo "${MAX_SCORE[@]}" | rev |cut -d"-" -f1|rev | sort -r | head -n1)" + + # Set noun-plurality agreement for grammar + DETECTIONS="$(ls -1 ${EXTRACTED}/By_Date/*/${SPECIES} | wc -l)" + if [ ${DETECTIONS} = 1 ];then + verbage=detection + else + verbage=detections + fi + + # Write results to temporary file + echo "${DETECTIONS} $verbage for ${SPECIES//_/ } | max conf ${MAX_SCORE}%" + done < "${IDFILE}" > ${TMP_FILE} + + # Print temporary file sorted by # of detections + sort -rk1 -h "${TMP_FILE}" + fi + echo + echo -n "Listening since "${INSTALL_DATE}"" + sleep 20 + clear +done \ No newline at end of file diff --git a/scripts/clear_all_data.php b/scripts/clear_all_data.php new file mode 100644 index 0000000..606aa78 --- /dev/null +++ b/scripts/clear_all_data.php @@ -0,0 +1,4 @@ + diff --git a/scripts/clear_all_data.sh b/scripts/clear_all_data.sh index b43bc25..4584d70 100755 --- a/scripts/clear_all_data.sh +++ b/scripts/clear_all_data.sh @@ -4,38 +4,23 @@ # you are okay will losing all the data that you've collected and processed # so far. source /etc/birdnet/birdnet.conf - -echo " -This script removes all data that has been collected. It is tantamount to -starting all data-collection from scratch. Only run this if you are sure -you are okay with losing all the data that you've collected and processed -so far. - -" -read -n1 -p "Are you sure you want to wipe away ALL data?" YN -echo -while true; do - case $YN in - [Yy]) break;; - *) echo "Exiting since you didn't answer with Y or y." && exit;; - esac -done - echo "Stopping services" sudo systemctl stop birdnet_recording.service echo "Removing all data . . . " sudo rm -drf "${RECS_DIR}" rm "${IDFILE}" - echo "Recreating necessary directories" -[ -d ${RECS_DIR} ] || mkdir -p ${RECS_DIR} -[ -d ${EXTRACTED} ] || mkdir -p ${EXTRACTED} -[ -d ${EXTRACTED}/By_Date ] || mkdir -p ${EXTRACTED}/By_Date -[ -d ${EXTRACTED}/By_Common_Name ] || mkdir -p ${EXTRACTED}/By_Common_Name -[ -d ${EXTRACTED}/By_Scientific_Name ] || mkdir -p ${EXTRACTED}/By_Scientific_Name -[ -d ${PROCESSED} ] || mkdir -p ${PROCESSED} -cp ~/BirdNET-Lite/templates/index.html ${EXTRACTED}/ - +[ -d ${RECS_DIR} ] || sudo -u ${BIRDNET_USER} mkdir -p ${RECS_DIR} +[ -d ${EXTRACTED} ] || sudo -u ${BIRDNET_USER} mkdir -p ${EXTRACTED} +[ -d ${EXTRACTED}/By_Date ] || sudo -u ${BIRDNET_USER} mkdir -p ${EXTRACTED}/By_Date +[ -d ${EXTRACTED}/By_Common_Name ] || sudo -u ${BIRDNET_USER} mkdir -p ${EXTRACTED}/By_Common_Name +[ -d ${EXTRACTED}/By_Scientific_Name ] || sudo -u ${BIRDNET_USER} mkdir -p ${EXTRACTED}/By_Scientific_Name +sudo -u ${BIRDNET_USER} ln -s /home/pi/BirdNET-Lite/templates/index.html ${EXTRACTED} +[ -d ${PROCESSED} ] || sudo -u ${BIRDNET_USER} mkdir -p ${PROCESSED} +[ -L ${EXTRACTED}/scripts ] || sudo -u ${BIRDNET_USER} ln -s /home/pi/BirdNET-Lite/scripts ${EXTRACTED}/ +[ -L ${EXTRACTED}/spectrogram.php ] || sudo -u ${BIRDNET_USER} ln -s /home/pi/BirdNET-Lite/scripts/spectrogram.php ${EXTRACTED} +[ -L ${EXTRACTED}/spectrogram.sh ] || sudo -u ${BIRDNET_USER} ln -s /home/pi/BirdNET-Lite/scripts/spectrogram.sh ${EXTRACTED} +sudo -u ${BIRDNET_USER} cp ~/BirdNET-Lite/templates/index.html ${EXTRACTED}/ echo "Restarting services" sudo systemctl restart birdnet_recording.service diff --git a/scripts/edit_birdnet.conf.php b/scripts/edit_birdnet.conf.php new file mode 100644 index 0000000..6fb7952 --- /dev/null +++ b/scripts/edit_birdnet.conf.php @@ -0,0 +1,4 @@ + diff --git a/scripts/edit_birdnet.conf.sh b/scripts/edit_birdnet.conf.sh new file mode 100755 index 0000000..197b706 --- /dev/null +++ b/scripts/edit_birdnet.conf.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +sudo systemctl start edit_birdnet_conf.service diff --git a/scripts/extract_new_birdsounds.sh b/scripts/extract_new_birdsounds.sh index a7ff429..baf2b12 100755 --- a/scripts/extract_new_birdsounds.sh +++ b/scripts/extract_new_birdsounds.sh @@ -3,12 +3,13 @@ #set -x set -e # Keep track of the last executed command -trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG -# Echo an error message before exiting -trap 'echo "\"${last_command}\" command exited with code $?."' EXIT +#trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG +## Echo an error message before exiting +#trap 'echo "\"${last_command}\" command exited with code $?."' EXIT # Remove temporary file trap 'rm -f $TMPFILE' EXIT source /etc/birdnet/birdnet.conf +[ -z ${RECORDING_LENGTH} ] && RECORDING_LENGTH=12 # Set Variables TMPFILE=$(mktemp) @@ -73,7 +74,7 @@ for h in "${SCAN_DIRS[@]}";do START="$(echo "${line}" | awk -F\; '!/birdnet/{print $1}')" END="$(echo "${line}" | awk -F\; '!/birdnet/{print $2}')" COMMON_NAME=""$(echo ${line} \ - | awk -F\; '!/birdnet/{print $4}')"" + | awk -F\; '!/birdnet/{print $4}'|tr -d "'")"" SCIENTIFIC_NAME=""$(echo ${line} \ | awk -F\; '!/birdnet/{print $3}')"" CONFIDENCE=""$(echo ${line} \ @@ -115,10 +116,10 @@ for h in "${SCAN_DIRS[@]}";do # If there are already 20 extracted entries for a given species # for today, remove the oldest file and create the new one. - # if [[ "$(find ${NEWSPECIES_BYDATE} | wc -l)" -ge 21 ]];then + # if [[ "$(find ${NEWSPECIES_BYDATE} | wc -l)" -ge 20 ]];then # echo "20 ${SPECIES}s, already! Removing the oldest by-date and making a new one" # cd ${NEWSPECIES_BYDATE} || exit 1 - # ls -1t . | tail -n +21 | xargs -r rm -vv + # ls -1t . | tail -n +20 | xargs -r rm -vv # fi echo "Extracting audio . . . " @@ -127,34 +128,48 @@ for h in "${SCAN_DIRS[@]}";do # structured by-species, symbolic links are made to populate the new # directory. - ### TESTING longer extraction context + # This section sets the SPACER that will be used to pad the audio clip with + # context. If EXTRACTION_LENGTH is 10, for instance, 3 seconds are removed + # from that value and divided by 2, so that the 3 seconds of the call are + # within 3.5 seconds of audio context before and after. [ -z ${EXTRACTION_LENGTH} ] && EXTRACTION_LENGTH=6 SPACER=$(echo "scale=1;(${EXTRACTION_LENGTH} - 3 )/2" |bc -l) START=$(echo "scale=1;${START} - ${SPACER}"|bc -l) END=$(echo "scale=1;${END} + ${SPACER}"|bc -l) - if (( $(echo "scale=1;${START} < 1" | bc -l) ));then START=0;fi - if (( $(echo "scale=1;${END} > ${RECORDING_LENGTH}" | bc -l) ));then END=${RECORDING_LENGTH};fi + # If the SPACER would have the START value less that 0, start at the + # beginning of the audio file. If the SPACER would make the END value + # exceed the end of the audio file, end the extraction at the end of the + # audio file. + if (( $(echo "${START} < 1" | bc -l) ));then START=0;fi + if (( $(echo "${END} > ${RECORDING_LENGTH}" | bc -l) ));then END=${RECORDING_LENGTH};fi ffmpeg -hide_banner -loglevel error -nostdin -i "${h}/${OLDFILE}" \ -acodec copy -ss "${START}" -to "${END}"\ "${NEWSPECIES_BYDATE}/${a}-${NEWFILE}" - if [[ "$(find ${NEWSPECIES_BY_COMMON} | wc -l)" -ge 21 ]];then + + + # Remove the oldest symbolic links that would made the directory have more + # than 20 entries. + if [[ "$(find ${NEWSPECIES_BY_COMMON} | wc -l)" -ge 20 ]];then echo "20 ${SPECIES}s, already! Removing the oldest by-species and making a new one" cd ${NEWSPECIES_BY_COMMON} || exit 1 - ls -1t . | tail -n +21 | xargs -r rm -vv + ls -1t . | tail -n +20 | xargs -r rm -vv ln -fs "${NEWSPECIES_BYDATE}/${a}-${NEWFILE}"\ "${NEWSPECIES_BY_COMMON}/${a}-${NEWFILE}" echo "Success! New extraction for ${COMMON_NAME}" else + # Make symbolic link of the extraction to add to By_Common_Name ln -fs "${NEWSPECIES_BYDATE}/${a}-${NEWFILE}"\ "${NEWSPECIES_BY_COMMON}/${a}-${NEWFILE}" fi - if [[ "$(find ${NEWSPECIES_BY_SCIENCE} | wc -l)" -ge 21 ]];then + # Remove the oldest symbolic links that would made the directory have more + # than 20 entries. + if [[ "$(find ${NEWSPECIES_BY_SCIENCE} | wc -l)" -ge 20 ]];then echo "20 ${SPECIES}s, already! Removing the oldest by-species and making a new one" cd ${NEWSPECIES_BY_SCIENCE} || exit 1 - ls -1t . | tail -n +21 | xargs -r rm -vv + ls -1t . | tail -n +20 | xargs -r rm -vv ln -fs "${NEWSPECIES_BYDATE}/${a}-${NEWFILE}"\ "${NEWSPECIES_BY_SCIENCE}/${a}-${NEWFILE}" echo "Success! New extraction for ${COMMON_NAME}" diff --git a/scripts/index.html b/scripts/index.html index 2fe3bd7..dbda4d2 100644 --- a/scripts/index.html +++ b/scripts/index.html @@ -1,3 +1,7 @@ +
+ +
+
@@ -18,6 +22,10 @@ +
+ +
+
@@ -25,4 +33,3 @@
- diff --git a/scripts/install_services.sh b/scripts/install_services.sh index e4d8ffb..9aaae79 100755 --- a/scripts/install_services.sh +++ b/scripts/install_services.sh @@ -79,6 +79,7 @@ create_necessary_dirs() { [ -d ${EXTRACTED}/By_Scientific_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Scientific_Name [ -d ${PROCESSED} ] || sudo -u ${USER} mkdir -p ${PROCESSED} [ -L ${EXTRACTED}/scripts ] || sudo -u ${USER} ln -s $(dirname ${my_dir})/scripts ${EXTRACTED} + [ -L ${EXTRACTED}/spectrogram.php ] || sudo -u ${USER} ln -s $(dirname ${my_dir})/scripts/spectrogram.* ${EXTRACTED} } install_alsa() { @@ -196,6 +197,9 @@ ${EXTRACTIONS_URL} { basicauth /Processed* { birdnet ${HASHWORD} } + basicauth /scripts* { + birdnet ${HASHWORD} + } basicauth /stream { birdnet ${HASHWORD} } @@ -209,6 +213,9 @@ http://birdnetsystem.local { basicauth /Processed* { birdnet ${HASHWORD} } + basicauth /scripts* { + birdnet ${HASHWORD} + } basicauth /stream { birdnet ${HASHWORD} } @@ -311,7 +318,7 @@ RestartSec=3 Type=simple User=${USER} Environment=TERM=xterm-256color -ExecStart=/usr/local/bin/gotty -p 9090 --title-format "BirdNET-Lite Statistics" /usr/local/bin/birdnet_stats.sh +ExecStart=/usr/local/bin/gotty -p 9090 --title-format "BirdNET-Lite Statistics" tmux new -A -s birdstats /usr/local/bin/birdnet_stats.sh [Install] WantedBy=multi-user.target @@ -319,6 +326,29 @@ EOF systemctl enable --now birdstats.service } +install_tmux() { + echo "Installing tmux dependencies" + apt -qqy install libevent-2* \ + libevent-dev \ + ncurses-bin \ + ncurses-base \ + ncurses-term \ + libncurses-dev + + cp $(dirname ${my_dir})/templates/tmux.conf /etc/tmux.conf +} + +install_sox() { + if which sox &> /dev/null;then + echo "Sox is installed" + else + echo "Installing sox" + apt -qq update + apt install -y sox + echo "Sox installed" + fi +} + install_php() { if ! which pip &> /dev/null || ! which php-fpm7.3;then echo "Installing PHP and PHP-FPM" @@ -337,6 +367,25 @@ EOF chmod 0440 /etc/sudoers.d/010_caddy-nopasswd } +install_edit_birdnet_conf() { + cat << EOF > /etc/systemd/system/edit_birdnet_conf.service +[Unit] +Description=Edit birdnet.conf + +[Service] +Restart=on-failure +RestartSec=3 +Type=simple +User=pi +Environment=TERM=xterm-256color +ExecStart=/usr/local/bin/gotty -w -p 9898 --title-format "Edit birdnet.conf" tmux new -A -s editbirdnet nano /home/pi/BirdNET-Lite/birdnet.conf + +[Install] +WantedBy=multi-user.target +EOF +} + + install_icecast() { if ! which icecast2;then echo "Installing IceCast2" @@ -443,7 +492,10 @@ install_selected_services() { install_Caddyfile install_avahi_aliases install_gotty_logs + install_tmux + install_sox install_php + install_edit_birdnet_conf fi if [ ! -z "${ICE_PWD}" ];then diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php new file mode 100644 index 0000000..3bf3804 --- /dev/null +++ b/scripts/spectrogram.php @@ -0,0 +1,4 @@ + diff --git a/scripts/spectrogram.sh b/scripts/spectrogram.sh new file mode 100755 index 0000000..8c15982 --- /dev/null +++ b/scripts/spectrogram.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Make sox spectrogram +source /etc/birdnet/birdnet.conf +analyzing_now="$(cat /home/pi/BirdNET-Lite/analyzing_now.txt)" +spectrogram_png=${EXTRACTED}/spectrogram.png +sudo -u pi sox "${analyzing_now}" -n spectrogram -o "${spectrogram_png}" diff --git a/scripts/tmux b/scripts/tmux new file mode 100755 index 0000000..fc178d4 Binary files /dev/null and b/scripts/tmux differ diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index 12de144..045699c 100755 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -7,9 +7,12 @@ SCRIPTS=(birdnet_analysis.sh birdnet_recording.sh birdnet_stats.sh cleanup.sh +clear_all_data.php clear_all_data.sh disk_usage.sh dump_logs.sh +edit_birdnet.conf.php +edit_birdnet.conf.sh extract_new_birdsounds.sh install_birdnet.sh install_config.sh @@ -31,7 +34,10 @@ restart_extraction.php restart_extraction.sh restart_services.php restart_services.sh +shutdown_system.php +shutdown_system.sh species_notifier.sh +tmux uninstall.sh update_species.sh ${HOME}/.gotty) @@ -51,6 +57,7 @@ birdstats.service birdterminal.service caddy.d caddy.service +edit_birdnet_conf.service extraction_log.service extraction.d extraction.service @@ -89,8 +96,8 @@ remove_icecast() { remove_scripts() { for i in "${SCRIPTS[@]}";do - if [ -L "${i}" ];then - sudo rm -v "${i}" + if [ -L "/usr/local/bin/${i}" ];then + sudo rm -v "/usr/local/bin/${i}" fi done } diff --git a/templates/index.html b/templates/index.html index c7fae41..f44b736 100644 --- a/templates/index.html +++ b/templates/index.html @@ -54,6 +54,16 @@ h1 { color: #999; } +h2 { + padding-left: 5%; + font-size: 16px; + font-weight: normal; + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; + color: #999; +} + h1 a { color: #000; margin: 0 4px; @@ -128,12 +138,13 @@ td { } td:nth-child(2) { - width: 80%; + width: 100%; } td:nth-child(3), th:nth-child(3) { - padding: 0 20px 0 20px; + #padding: 0 20px 0 20px; + width: 0px; } th:nth-child(4), @@ -269,9 +280,9 @@ footer { - - - + + + @@ -311,30 +322,25 @@ footer { BirdNET-Lite System +

+ + Live Audio Stream + +

+

+ + BirdNET-system Report + +

-
-
- 5 directories - 1 file - -
-
- - - @@ -346,9 +352,6 @@ footer { By_Common_Name - - - @@ -358,9 +361,6 @@ footer { By_Date - - - @@ -370,45 +370,61 @@ footer { By_Scientific_Name - - - - - - + + + + + + + + - - - - - - + + + + + + + +
- - Name + Extractions - Size - - Modified -
- + Processed
+ Tools +
- + scripts
- - - stream + + + birdlog 0 B
+ + + extractionlog + +
+
+ +
+ +
diff --git a/version b/version new file mode 100644 index 0000000..51b2609 --- /dev/null +++ b/version @@ -0,0 +1,2 @@ +rpialpha +Thu 07 Oct 2021 04:09:31 PM EDT