#!/bin/bash
+
+# perl package manager put this here?
+# PATH="/home/iank/perl5/bin${PATH:+:${PATH}}"; export PATH;
+# PERL5LIB="/home/iank/perl5/lib/perl5${PERL5LIB:+:${PERL5LIB}}"; export PERL5LIB;
+# PERL_LOCAL_LIB_ROOT="/home/iank/perl5${PERL_LOCAL_LIB_ROOT:+:${PERL_LOCAL_LIB_ROOT}}"; export PERL_LOCAL_LIB_ROOT;
+# PERL_MB_OPT="--install_base \"/home/iank/perl5\""; export PERL_MB_OPT;
+# PERL_MM_OPT="INSTALL_BASE=/home/iank/perl5"; export PERL_MM_OPT;
+
# I, Ian Kelling, follow the GNU license recommendations at
# https://www.gnu.org/licenses/license-recommendations.en.html. They
# recommend that small programs, < 300 lines, be licensed under the
--- /dev/null
+
+multiline = 0
+# i like it, but it randomly got mostly stuck on bright blue.
+theme = Solarized
+#colored = 0
+
+
+show_dualvar = off
+caller_message_newline = 0
+print_escapes = 0
+
+
+# testing. not sure if I want htis.
+show_reftype = 1
+
+# recommended by the manual.
+filters = DateTime
+
+# copied docs of use_prototypes:
+# p { foo => 1 }; # works, but now p(@foo) will fail, you must always pass a ref,
+# e.g. p(\@foo)
+# end docs. Looking in the source code,
+# we don't need reference for single arguments. But
+# beware that lists automatically become multiple arguments.
+use_prototypes = 0
+
+caller_info = 1
+
+theme = Iank
+
+caller_message = __FILENAME__:__LINE__
+
+scalar_quotes = '
+
+string_max = 400000
+array_max = 400
+hash_max = 400
+string_overflow = (.IANK-DDP.. __SKIPPED__ chars...)
--- /dev/null
+-- wraps long columns. so nice.
+\pset format wrapped
name="$1"
shift
# shellcheck disable=SC2034 # unused from beetag, don't care for now.
- bpla[$name]="${*@Q}"
+ bpla[$name]="$*"
}
# otherwise it is redundant.
#. /a/c/fsf-script-lib
+
+# todo: what the hell is going on here: I think I accidentally pressed r
+# for rock, then wanted to set it back, so I pressed the button for
+# dance.
+#
+#beetmq id:19324 rock=t
+# rock: t
+#beetmq id:19324 genre=dance
+#No changes to make.
+
+
# Must be called from beetag for variables to be setup
beetag-help() {
source /a/bin/ds/beet-data
# setting this also sets dotglob.
export GLOBIGNORE="*/.:*/.."
+
+
+PATH="/home/iank/perl5/bin${PATH:+:${PATH}}"; export PATH;
+PERL5LIB="/home/iank/perl5/lib/perl5${PERL5LIB:+:${PERL5LIB}}"; export PERL5LIB;
+PERL_LOCAL_LIB_ROOT="/home/iank/perl5${PERL_LOCAL_LIB_ROOT:+:${PERL_LOCAL_LIB_ROOT}}"; export PERL_LOCAL_LIB_ROOT;
+PERL_MB_OPT="--install_base \"/home/iank/perl5\""; export PERL_MB_OPT;
+PERL_MM_OPT="INSTALL_BASE=/home/iank/perl5"; export PERL_MM_OPT;
+
+
# Useful info. see man bash.
PS4='$LINENO+ '
done
}
-# note, there is also the tool gron which is meant for this, but
-# this is good enough to not bother installing another tool
-jq-lines() {
- # https://stackoverflow.com/questions/59700329/how-to-print-path-and-key-values-of-json-file-using-jq
- jq --stream -r 'select(.[1]|scalars!=null) | "\(.[0]|join(".")): \(.[1]|tojson)"' "$@"
-}
tsr() { # ts run
"$@" |& ts || return $?
# beet playlist. use beetag with a playlist name
bpl() {
local playlist playlist_regex
+ local -i i=1
+ local -a args
case $1 in
-h|--help)
for playlist in "${!bpla[@]}"; do
;;
esac
- playlist="${*: -1}"
+ for arg; do
+ if (( i == $# )); then
+ playlist="$arg"
+ break
+ fi
+ args+=("$arg")
+ i+=1
+ done
+
playlist_regex='[a-z0-9_]'
if [[ ! $playlist =~ $playlist_regex ]]; then
echo "bpl: error unexpected chars in playlist: $playlist"
return 1
fi
- # all but last arg as options
- e beetag -r "${*:1:$# - 1}" "${bpla[$playlist]}"
+
+ beetag -r "${args[@]}" ${bpla[$playlist]}
}
complete -W "${!bpla[*]}" bpl
# eg, previously rated > 1, now rated 1.
while read -r l; do
convertedpath="/i/converted${l#/i/m}"
- case $convertedpath in
- *.flac) convertedpath="${convertedpath%.flac}.mp3" ;;
- esac
+ if [[ $convertedpath == *.flac ]]; then
+ convertedpath="${convertedpath%.flac}.mp3"
+ fi
paths[$convertedpath]=t
done <"$tmpf"
local count artist artregex genre singleartist tmpf tmpf2
local -a artists genres
singleartist=false
- case $1 in
- artist:*)
- singleartist=true
- artist="$1"
- shift
- ;;
- esac
+ if [[ $1 == artist:* ]]; then
+ singleartist=true
+ artist="$1"
+ shift
+ fi
tmpf=$(mktemp)
tmpf2=$(mktemp)
if $singleartist; then
fi
done <$tmpf
read -r -N 1 -s -p "Y/n " char
- case $char in
- [Yy$'\n'])
- for (( i=0; i<${#artists[@]}; i++ )); do
- beet modify -y "$@" "artist::^${artists[i]}$" genre=${genre[i]}
- done
- ;;
- esac
+ if [[ $char == [Yy$'\n'] ]]; then
+ for (( i=0; i<${#artists[@]}; i++ )); do
+ beet modify -y "$@" "artist::^${artists[i]}$" genre=${genre[i]}
+ done
+ fi
fi
rm $tmpf
}
local arg
for arg; do
local zone=${arg#db.}
- local dir=/p/c/machine_specific/vps/filesystem/var/lib/bind
+ local dir=/p/c/user-specific/bind/var/lib/bind
dnssec-signzone -S -e +31536000 -o $zone -K $dir -d $dir $dir/db.$zone
done
}
} | u /p/c/dnsmasq-data
- b8_ip=$(dig +short b8.nz @iankelling.org | tail -1)
+ #b8_ip=$(dig +short b8.nz @iankelling.org | tail -1)
# if our dynamic ip updates broke, set manually, eg:
- #b8_ip=72.74.193.xxx
+ b8_ip=108.26.192.250 # 72.74.193.xxx
if [[ ! $b8_ip ]]; then
b8_ip=$(curl --connect-timeout 10 -s4 https://iankelling.org/cgi/pubip)
fi
# especially for links.
profr() {
source /p/c/domain-info
- case $HOSTNAME in
- $d_host)
- profr-local
- ;;
- *)
- ssh b8.nz profr-local
- ;;
- esac
+ if [[ $HOSTNAME == $d_host ]]; then
+ else
+ ssh b8.nz profr-local
+ fi
}
profr-local() {
local -a dirs search
ngset
- case $1 in
- u)
- search=(
- ~/.config/systemd/user.control/*
- $XDG_RUNTIME_DIR/systemd/user.control/*
- $XDG_RUNTIME_DIR/systemd/transient/*
- $XDG_RUNTIME_DIR/systemd/generator.early/*
- ~/.config/systemd/user/*
- /etc/systemd/user/*
- $XDG_RUNTIME_DIR/systemd/user/*
- /run/systemd/user/*
- $XDG_RUNTIME_DIR/systemd/generator/*
- ~/.local/share/systemd/user/*
- /usr/lib/systemd/user/*
- $XDG_RUNTIME_DIR/systemd/generator.late/*
- )
- ;;
- *)
- search=(
- /etc/systemd/system.control/*
- /run/systemd/system.control/*
- /run/systemd/transient/*
- /run/systemd/generator.early/*
- /etc/systemd/system/*
- /etc/systemd/systemd.attached/*
- /run/systemd/system/*
- /run/systemd/systemd.attached/*
- /run/systemd/generator/*
- /lib/systemd/system/*
- /run/systemd/generator.late/*
- )
- ;;
- esac
+ if [[ $1 == u ]]; then
+ search=(
+ ~/.config/systemd/user.control/*
+ $XDG_RUNTIME_DIR/systemd/user.control/*
+ $XDG_RUNTIME_DIR/systemd/transient/*
+ $XDG_RUNTIME_DIR/systemd/generator.early/*
+ ~/.config/systemd/user/*
+ /etc/systemd/user/*
+ $XDG_RUNTIME_DIR/systemd/user/*
+ /run/systemd/user/*
+ $XDG_RUNTIME_DIR/systemd/generator/*
+ ~/.local/share/systemd/user/*
+ /usr/lib/systemd/user/*
+ $XDG_RUNTIME_DIR/systemd/generator.late/*
+ )
+ else
+ search=(
+ /etc/systemd/system.control/*
+ /run/systemd/system.control/*
+ /run/systemd/transient/*
+ /run/systemd/generator.early/*
+ /etc/systemd/system/*
+ /etc/systemd/systemd.attached/*
+ /run/systemd/system/*
+ /run/systemd/systemd.attached/*
+ /run/systemd/generator/*
+ /lib/systemd/system/*
+ /run/systemd/generator.late/*
+ )
+ fi
for f in "${search[@]}"; do
[[ -d $f ]] || continue
- case $f in
- *.requires|*.wants)
- dirs+=("$f")
- ;;
- esac
+ if [[ $f == *.requires || $f == *.wants ]]; then
+ dirs+=("$f")
+ fi
done
# dirs is just so we write out the directory names, ls does it when there is 2 or more dirs.
- case ${#dirs[@]} in
- 1)
- echo "${dirs[0]}:"
- ll "${dirs[@]}"
- ;;
- 0) : ;;
- *)
- ll "${dirs[@]}"
- ;;
- esac
+ dirc=${#dirs[@]}
+ if (( dirc == 1 )); then
+ echo "${dirs[0]}:"
+ ll "${dirs[@]}"
+ elif (( dirc != 0 )); then
+ ll "${dirs[@]}"
+ fi
ngreset
}
# ensure no bad programs appending to this file will have an affect
return 0
+
+
+# finding the letter pages that have hardly any text due to overflow:
+letter-hac-fsf() {
+ pdftotext ISAL.pdf
+ awk 'BEGIN {page=1; words=0}
+/\f/ {print words, page; page++; words=0; next}
+{words += NF}
+END {print words, page}' ISAL.txt | sort -n
+}
# about 24 hours of failures
# it copies over its files without respecting symlinks, so
# we pass options to use different location.
-ExecStart=/usr/local/bin/sysd-mail-once -288 rss2email r2e -d /p/c/rss2email.json -c /p/c/rss2email.cfg run
+
+# Todo: we should wrap this in a script which ignores
+# persistent errors about parsing html. Not reporting any errors with sysd-mail-once until then.
+# Systemd also has an output filtering mechanism, we could try that.
+ExecStart=r2e -d /p/c/rss2email.json -c /p/c/rss2email.cfg run
+#ExecStart=/usr/local/bin/sysd-mail-once -288 rss2email r2e -d /p/c/rss2email.json -c /p/c/rss2email.cfg run
EOF
sd /etc/systemd/system/rss2email.timer <<'EOF'
[Unit]
# for initial run. required.
OnActiveSec=30
# for subsequent runs.
-OnUnitInactiveSec=300
+OnUnitInactiveSec=3000
[Install]
WantedBy=timers.target
# others unknown
esac
-case $distro in
- ubuntu|debian)
- e spacefm-gtk3 ;;
- arch)
- e spacefm ;;
-esac
-
-
case $(debian-codename) in
aramo)
e ncal ;;
--- /dev/null
+package Data::Printer::Theme::Iank;
+# inspired by Mattia Astorino's Iank theme:
+# https://github.com/material-theme/vsc-material-theme
+use strict;
+use warnings;
+
+sub colors {
+ my %code_for = (
+ base03 => '#1c1c1c', # '#002b36'
+ base02 => '#262626', # '#073642'
+ base01 => '#585858', # '#586e75'
+ base00 => '#626262', # '#657b83'
+ base0 => '#808080', # '#839496'
+ base1 => '#8a8a8a', # '#93a1a1'
+ base2 => '#e4e4e4', # '#eee8d5'
+ base3 => '#ffffd7', # '#fdf6e3'
+ yellow => '#af8700', # '#b58900'
+ orange => '#d75f00', # '#cb4b16'
+ red => '#d70000', # '#dc322f'
+ magenta => '#af005f', # '#d33682'
+ violet => '#5f5faf', # '#6c71c4'
+ blue => '#0087ff', # '#268bd2'
+ cyan => '#00afaf', # '#2aa198'
+ green => '#5f8700', # '#859900'
+ );
+
+ return {
+ array => $code_for{violet}, # array index numbers
+ number => $code_for{cyan}, # numbers
+ string => $code_for{magenta}, # strings
+ class => $code_for{yellow}, # class names
+ method => $code_for{orange}, # method names
+ undef => $code_for{red}, # the 'undef' value
+ hash => $code_for{green}, # hash keys
+ regex => $code_for{orange}, # regular expressions
+ code => $code_for{base2}, # code references
+ glob => $code_for{blue}, # globs (usually file handles)
+ vstring => $code_for{base1}, # version strings (v5.16.0, etc)
+ lvalue => $code_for{green}, # lvalue label
+ format => $code_for{green}, # format type
+ true => $code_for{blue}, # boolean type (true)
+ false => $code_for{blue}, # boolean type (false)
+ repeated => $code_for{red}, # references to seen values
+ caller_info => $code_for{undef}, # details on what's being printed
+ weak => $code_for{violet}, # weak references flag
+ tainted => $code_for{violet}, # tainted flag
+ unicode => $code_for{magenta}, # utf8 flag
+ escaped => $code_for{red}, # escaped characters (\t, \n, etc)
+ brackets => $code_for{base0}, # (), {}, []
+ separator => $code_for{base0}, # the "," between hash pairs, array elements, etc
+ quotes => $code_for{'base0'},
+ unknown => $code_for{red}, # any (potential) data type unknown to Data::Printer
+ };
+
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Data::Printer::Theme::Iank - Iank theme for DDP
+
+=head1 SYNOPSIS
+
+In your C<.dataprinter> file:
+
+ theme = Iank
+
+Or during runtime:
+
+ use DDP theme => 'Iank';
+
+=head1 DESCRIPTION
+
+This module implements the Iank theme for Data::Printer.
+
+=head1 SEE ALSO
+
+L<Data::Printer>
+
+L<Data::Printer::Theme>
subvolume d-r3
subvolume siterip
subvolume ar
-subvolume roverflow
--- /dev/null
+transaction_syslog local7
+
+lockfile /var/lock/btrbk-r4.lock
+
+timestamp_format long-iso
+
+snapshot_create onchange
+
+snapshot_preserve 18h 14d 8w 12m
+snapshot_preserve_min 2d
+snapshot_dir btrbk
+
+target_preserve 18h 14d 8w 12m
+target_preserve_min 2d
+
+rate_limit no
+volume /mnt/r4
+subvolume roverflow
Description=Btrbk r to rust timer
[Timer]
-OnCalendar=*-*-* 05:00:00 America/New_York
+OnCalendar=*-*-* 15:00:00 America/New_York
[Install]
WantedBy=timers.target
Description=Btrbk r2 timer
[Timer]
-OnCalendar=*-*-* 07:00:00 America/New_York
+OnCalendar=*-*-* 13:00:00 America/New_York
[Install]
WantedBy=timers.target
Description=Btrbk r3 timer
[Timer]
-OnCalendar=*-*-* 07:00:00 America/New_York
+OnCalendar=*-*-* 09:00:00 America/New_York
[Install]
WantedBy=timers.target
--- /dev/null
+[Unit]
+Description=Btrbk to r3
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/local/bin/sysd-mail-once btrbkr3 btrbk -c /etc/btrbk/r3.conf run
--- /dev/null
+[Unit]
+Description=Btrbk r4 timer
+
+[Timer]
+OnCalendar=*-*-* 11:00:00 America/New_York
+
+[Install]
+WantedBy=timers.target
[Unit]
-Description=Btrbk to rbackup
+Description=Snapshot subvolumes that have a primary location in /mnt/rbackup
After=multi-user.target
[Service]
Description=Btrbk rbackup timer
[Timer]
-OnCalendar=*-*-* 07:00:00 America/New_York
+OnCalendar=*-*-* 17:00:00 America/New_York
[Install]
WantedBy=timers.target
u /etc/spamassassin/mylocal.cf <<'EOF'
# this is mylocal.cf because the normal local.cf has a bunch of upstream stuff i dont want to mess with
+# get rid of syslog spam: spamd[159554]: check: dns_block_rule RCVD_IN_VALIDITY_SAFE_BLOCKED hit, creating /root/.spamassassin/dnsblock_sa-accredit.habeas.com (This means DNSBL blocked you due to too many queries. Set all affected rules score to 0, or use "dns_query_restriction deny sa-accredit.habeas.com" to disable queries)
+dns_query_restriction deny sa-accredit.habeas.com
# /usr/share/doc/exim4-base/README.Debian.gz:
# SpamAssassin's default report should not be used in a add_header
;;
esac
-u /etc/default/spamassassin <<EOF
-# defaults plus debugging flags for an issue im having
-OPTIONS="--create-prefs --max-children 5 --helper-home-dir${spamd_listen_arg}"
+u /etc/default/spamd <<EOF
+# defaults plus the spamd_list thing, and turn off its syslog logging which I'm annoyed at.
+
+OPTIONS="-s null --create-prefs --max-children 5 --helper-home-dir${spamd_listen_arg}"
PIDFILE="/run/spamd.pid"
# my additions
NICE="--nicelevel 15"
-# not used in t12+, that uses
-# /usr/lib/systemd/system/spamassassin-maintenance.timer
-CRON=1
+
EOF
case $HOSTNAME in
{
if [[ $HOSTNAME == "$MAIL_HOST" ]]; then
+ # begin dovecot settings
cat <<'EOF'
+listen = 127.0.0.1, ::1, 10.8.0.4
+
+info_log_path = /dev/null
+
ssl_cert = </etc/exim4/fullchain.pem
ssl_key = </etc/exim4/privkey.pem
EOF
awk '$1 == "Symbol:" && $2 !~ /\(0\.00\)/ && $3 !~ /\(0\.00\)/ {print $2}' | sed 's/(.*//'
}
+deactivated_sshd=false
+lock_check_fails=0
+
+maybe-toggle-ssh() {
+
+ # something went wrong in this case.
+ if (( lock_check_fails >= 20 )); then
+ systemctl enable --now ssh.socket
+ systemctl start ssh.service
+ fi
+ export DISPLAY=:0
+ export XAUTHORITY=/home/iank/.Xauthority
+
+ if ! lock_info=$(xscreensaver-command -time 2>/dev/null); then
+ lock_check_fails+=1
+ return 0
+ fi
+
+ lock_or_unlock_time=$(echo "$lock_info" | grep -o 'since.*' | sed 's/since //')
+ lock_or_unlock_time=$(date -d "$lock_or_unlock_time" +%s 2>/dev/null ||:)
+ uint_regex='^[0-9]+$'
+ if [[ ! $lock_or_unlock_time =~ $uint_regex ]]; then
+ lock_check_fails+=1
+ return 0
+ fi
+ lock_check_fails=0
+
+ if [[ $lock_info == *non-blanked* ]]; then
+ if ! $deactivated_sshd; then
+ deactivated_sshd=true
+ if systemctl is-active ssh; then
+ systemctl disable --now ssh.socket
+ systemctl stop ssh.service
+ fi
+ fi
+ # if its been blanked more than a few minutes while I'm afk turn ssh back on.
+ elif $deactivated_sshd && (( EPOCHSECONDS - lock_or_unlock_time > 60 * 2 )); then
+ deactivated_sshd=false
+ if ! systemctl is-active ssh; then
+ systemctl enable --now ssh.socket
+ systemctl start ssh.service
+ fi
+ fi
+}
+
rspamc-process() {
# note, this could in theory break since we aren't limiting it to the
sleep 10
while true; do
premain_sec=$EPOCHSECONDS
+ maybe-toggle-ssh
main
maini=$((maini + 1))
sleep $(( 300 - ( EPOCHSECONDS - premain_sec ) ))
expect
# for ftp upload dejagnu test
libdate-manip-perl libemail-messageid-perl
+ libdata-printer-perl
+ libautovivification-perl
+ libdata-types-perl
+ libdbd-pg-perl
+ libfile-libmagic-perl
fakeroot
fail2ban
fdupes
gnome-screenshot
# color picker
gpick
+ gron
grepmail
guvcview
gwenview
knot-dnsutils
libterm-readkey-perl
libreoffice
+ libreoffice-help-en-us
linphone-desktop
linux-doc
lshw
--- /dev/null
+#!/usr/bin/perl
+use warnings FATAL => 'all';
+use 5.038;use Digest::SHA;print Digest::SHA->new(256)->addfile($ARGV[0], "b")->hexdigest;
set -e; . /usr/local/lib/bash-bear; set +e
-mpv --speed=1 --no-terminal --vo=null --volume=90 /a/bin/data/d20.wav
+mpv --speed=1 --no-terminal --vo=null --volume=60 /a/bin/data/d20.wav
+++ /dev/null
--- mark for folder 4
-local like1_file = "/t/mpvlike1.log"
-mp.add_key_binding("v", "write_filename", function()
- local filepath = mp.get_property("path")
- -- Convert to absolute path if it's not already
- if filepath and not filepath:match("^/") and not filepath:match("^%a:") then
- local working_dir = mp.get_property("working-directory")
- if working_dir then
- filepath = working_dir .. "/" .. filepath
- end
-
- local file = io.open(like1_file, "a") -- Open the file in append mode
- file:write(filepath .. "\n") -- Write the filename with a newline
- file:close()
- end
-end)
+++ /dev/null
--- mark for folder 3
-local like2_file = "/t/mpvlike2.log"
-mp.add_key_binding("x", "write_filename", function()
- local filepath = mp.get_property("path")
- -- Convert to absolute path if it's not already
- if filepath and not filepath:match("^/") and not filepath:match("^%a:") then
- local working_dir = mp.get_property("working-directory")
- if working_dir then
- filepath = working_dir .. "/" .. filepath
- end
-
- local file = io.open(like2_file, "a") -- Open the file in append mode
- file:write(filepath .. "\n") -- Write the filename with a newline
- file:close()
- end
-end)
+++ /dev/null
--- mark for deletion
-local like3_file = "/t/mpvlike3.log"
-mp.add_key_binding("d", "write_filename", function()
- local filepath = mp.get_property("path")
- -- Convert to absolute path if it's not already
- if filepath and not filepath:match("^/") and not filepath:match("^%a:") then
- local working_dir = mp.get_property("working-directory")
- if working_dir then
- filepath = working_dir .. "/" .. filepath
- end
-
- local file = io.open(like3_file, "a") -- Open the file in append mode
- file:write(filepath .. "\n") -- Write the filename with a newline
- file:close()
- end
-end)
if ((qlen)); then
# Do sending of long delayed messages, and dont count them in our queue warnings.
for mid in $(exiqgrep -o 2400 -zi); do
+ # if we get annoying erors like this, we can redirect the awk sterr to null.
+ # awk: cmd. line:1: (FILENAME=- FNR=19) warning: Invalid multibyte data detected. There may be a mismatch between your data and your locale
if exim -Mvh $mid | awk 'tolower($2) == "fdate:"' | grep -q .; then
qlen=$(( qlen - 1 ))
# shellcheck disable=SC2016 # exim var, not a bash bar
begin=false
# todo: make this robust to the case of /a not being mounted
- if ! make -C /b/ds -q ~/.local/distro-begin 2>/dev/null || [[ $(<~/.local/distro-begin) != 0 ]]; then
+ if ! make --no-print-directory -C /b/ds -q ~/.local/distro-begin 2>/dev/null || [[ $(<~/.local/distro-begin) != 0 ]]; then
begin=true
fi
end=false
- if ! make -C /b/ds -q ~/.local/distro-end 2>/dev/null || [[ $(<~/.local/distro-end) != 0 ]]; then
+ if ! make --no-print-directory -C /b/ds -q ~/.local/distro-end 2>/dev/null || [[ $(<~/.local/distro-end) != 0 ]]; then
end=true
fi
} # end write-status
+deactivated_sshd=false
+lock_check_fails=0
+
# This prevents me having to mute notifications when I'm going to bed.
mute() {
local locked