remove kinsis / unused input settings
[distro-setup] / brc
diff --git a/brc b/brc
index 67a113f7a2a4839f515cd61909d0b453dcb74ea2..fbc1acb2f653cc50467d6aeb9f6ff036cfc32c7a 100644 (file)
--- a/brc
+++ b/brc
@@ -109,18 +109,24 @@ if [[ $- == *i* ]]; then
         bind 'set print-completions-horizontally on'
         bind '"\C-i": self-insert'
     else
-        # arrow keys. for other terminals, see http://unix.stackexchange.com/questions/10806/how-to-change-previous-next-word-shortcut-in-bash
+        # sakura == xterm-256color
+        # konsole == xterm
         if [[ $TERM == "xterm" ]]; then
+            # control + arrow keys. for other terminals, see http://unix.stackexchange.com/questions/10806/how-to-change-previous-next-word-shortcut-in-bash
             bind '"\e[1;5C": shell-forward-word' 2>/dev/null
             bind '"\e[1;5D": shell-backward-word' 2>/dev/null
         else
+            # make ctrl-backspace work. for konsole, i fixed it through
+# /home/iank/.local/share/konsole/default.keytab
+            stty werase '^h'
             bind '"\eOc": shell-forward-word'
             bind '"\eOd": shell-backward-word'
         fi
-        # terminal keys: C-c, C-z. the rest defined by stty -a are, at least in
+        # i can't remember why i did this, probably to free up some keys to bind
+        # to other things in bash.
+        # other than C-c and C-z, the rest defined by stty -a are, at least in
         # gnome-terminal, overridden by bash, or disabled by the system
-        stty werase undef lnext undef stop undef start undef
-
+        stty  lnext undef stop undef start undef
     fi
 
 fi
@@ -170,6 +176,7 @@ source $(dirname $(readlink -f $BASH_SOURCE))/path_add-function
 source /a/bin/log-quiet/logq-function
 path_add /a/exe
 path_add --ifexists --end /a/opt/adt-bundle*/tools /a/opt/adt-bundle*/platform-tools
+export WCDHOME=/a
 # based on readme.debian. dunno if this will break on other distros.
 _x=/usr/share/wcd/wcd-include.sh
 if [[ -e $_x ]]; then source $_x; fi
@@ -269,12 +276,18 @@ _cdiff-prep() {
 
 _khfix_common() {
     local h=${1##*@}
+    local x
     ssh-keygen -R $h -f $(readlink -f ~/.ssh/known_hosts)
-    local x=$(timeout 0.1 ssh -v $1 |& sed -rn "s/debug1: Connecting to $h \[([^\]*)].*/\1/p");
+    x=$(timeout 1 ssh -oBatchMode=yes -oControlMaster=no -oControlPath=/ -v $1 |& sed -rn "s/debug1: Connecting to $h \[([^\]*)].*/\1/p")
+    if [[ ! $x ]]; then
+        echo "khfix: ssh failed"
+        return 1
+    fi
+    echo "khfix: removing key for $x"
     ssh-keygen -R $x -f $(readlink -f ~/.ssh/known_hosts)
 }
 khfix() { # known hosts fix
-    _khfix_common "$@"
+    _khfix_common "$@" || return 1
     ssh $1 :
 }
 khcopy() {
@@ -288,6 +301,14 @@ a() {
 
 ack() { ack-grep "$@"; }
 
+anki() {
+    if which anki &>/dev/null; then
+        command anki
+    else
+        schroot -c anki -- anki
+    fi
+}
+
 astudio() {
     # googling android emulator libGL error: failed to load driver: r600
     # lead to http://stackoverflow.com/a/36625175/14456
@@ -307,20 +328,45 @@ bkrun() {
 
 bfg() { java -jar /a/opt/bfg-1.12.14.jar "$@"; }
 
+bigclock() {
+    xclock -digital -update 1 -face 'arial black-80:bold'
+}
+
 btc() {
     local f=/etc/bitcoin/bitcoin.conf
-    bitcoin-cli -$(s grep rpcuser= $f) -$(s grep rpcpassword= $f) "$@"
+    # importprivkey will timeout if using the default of 15 mins.
+    # upped it to 1 hour.
+    bitcoin-cli -rpcclienttimeout=60000 -$(s grep rpcuser= $f) -$(s grep rpcpassword= $f) "$@"
 }
 
-btcusd() {
+btcusd() { # $1 btc in usd
     local price
-    price="$(curl -s https://blockchain.info/ticker | jq .USD.last)"
+    price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
     printf "$%s\n" "$price"
     if [[ $1 ]]; then
-        printf "$%.2f\n" "$(echo "scale=2; $price * $1"| bc -l)"
+        printf "$%.2f\n" "$(echo "scale=4; $price * $1"| bc -l)"
+    fi
+}
+usdbtc() { # $1 usd in btc
+    local price
+    price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
+    printf "$%s\n" "$price"
+    if [[ $1 ]]; then
+        # 100 mil satoshi / btc. 8 digits after the 1.
+        printf "%.8f btc\n" "$(echo "scale=10; $1 / $price "| bc -l)"
+    fi
+}
+satoshi() { # $1 satoshi in usd
+    local price
+    price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
+    price=$(echo "scale=10; $price * 0.00000001"| bc -l)
+    printf "$%f\n" "$price"
+    if [[ $1 ]]; then
+        printf "$%.2f\n" "$(echo "scale=10; $price * $1"| bc -l)"
     fi
 }
 
+
 # c. better cd
 if [[ $RLC_INSIDE_EMACS ]]; then
     c() { wcd -c -z 50 -o "$@"; }
@@ -331,6 +377,14 @@ fi
 
 caa() { git commit --amend --no-edit -a; }
 
+caf() {
+    find -L $1 -type f -not \( -name .svn -prune -o -name .git -prune \
+         -o -name .hg -prune -o -name .editor-backups -prune \
+         -o -name .undo-tree-history -prune \) \
+         -exec bash -lc 'hr; echo "$1"; hr; cat "$1"' _ {} \; 2>/dev/null
+
+}
+
 calc() { echo "scale=3; $*" | bc -l; }
 # no having to type quotes, but also no command history:
 clc() {
@@ -344,7 +398,7 @@ cam() {
 }
 
 ccat () { # config cat. see a config without extra lines.
-    grep '^\s*[^[:space:]#]' "$@"
+    grep '^\s*[^;[:space:]#]' "$@"
 }
 
 cdiff() {
@@ -401,6 +455,16 @@ cl() {
     c =
 }
 
+chrome() {
+    if type -p chromium &>/dev/null; then
+        cmd=chromium
+    else
+        cd
+        cmd="schroot -c stretch chromium"
+        CHROMIUM_FLAGS='--enable-remote-extensions' $cmd &r
+    fi
+}
+
 d() { builtin bg; }
 complete -A stopped -P '"%' -S '"' d
 
@@ -450,7 +514,7 @@ dt() {
     date "+%A, %B %d, %r" "$@"
 }
 
-dus() {
+dus() { # du, sorted, default arg of
     du -sh ${@:-*} | sort -h
 }
 
@@ -474,6 +538,11 @@ envload() { # load environment from a previous: export > file
     done < "$file"
 }
 
+# mail related
+etail() {
+    sudo tail -f /var/log/exim4/mainlog
+}
+
 f() {
     # cd forward
     c +
@@ -489,10 +558,99 @@ fa() {
 }
 
 faf() { # find all files
-    find $@ -type f
+    find -L $1 -not \( -name .svn -prune -o -name .git -prune \
+         -o -name .hg -prune -o -name .editor-backups -prune \
+         -o -name .undo-tree-history -prune \) 2>/dev/null
+}
+
+# one that comes with distros is too old for newer devices
+fastboot() {
+    /a/opt/android-platform-tools/fastboot "$@";
+}
+
+
+# List of apps to install/update
+# Create from existing manually installed apps by doing
+# fdroidcl search -i, then manually removing
+# automatically installed/preinstalled apps
+
+# firefox updater. commented out, firefox depends on nonfree opengl.
+# de.marmaro.krt.ffupdater
+# # causes replicant to die on install and go into a boot loop
+# me.ccrama.redditslide
+#
+# # my attempt at recovering from boot loop:
+# # in that case, boot to recovery (volume up, home button, power, let go of power after samsun logo)
+# # then
+# mount /dev/block/mmcblk0p12 /data
+# cd /data
+# find -iname '*appname*'
+# rm -rf FOUND_DIRS
+# usually good enough to just rm -rf /data/app/APPNAME
+#
+# currently broken:
+#at.bitfire.davdroid
+fdroid_pkgs=(
+    com.alaskalinuxuser.justnotes
+    com.artifex.mupdfdemo
+    com.fsck.k9
+    com.ichi2.anki
+    com.jmstudios.redmoon
+    com.notecryptpro
+    com.nutomic.syncthingandroid
+    com.termux
+    com.zoffcc.applications.zanavi
+    cz.martykan.forecastie
+    de.danoeh.antennapod
+    im.vector.alpha # riot
+    info.papdt.blackblub
+    me.tripsit.tripmobile
+    net.gaast.giggity
+    net.osmand.plus
+    net.sourceforge.opencamera
+    org.dmfs.tasks # caldav tasks thing
+    org.fdroid.fdroid
+    org.isoron.uhabits
+    org.kde.kdeconnect_tp
+    org.quantumbadger.redreader
+    org.smssecure.smssecure
+    org.fedorahosted.freeotp
+)
+# https://forum.xda-developers.com/android/software-hacking/wip-selinux-capable-superuser-t3216394
+# for maru,
+#me.phh.superuser
+
+fdup() {
+    local -A installed updated
+    local p
+    fdroidcl update
+    for p in $(fdroidcl search -i| grep -o "^\S\+"); do
+        installed[$p]=true
+    done
+    for p in $(fdroidcl search -u| grep -o "^\S\+"); do
+        updated[$p]=false
+    done
+    for p in ${fdroid_pkgs[@]}; do
+        ${installed[$p]:-false} || fdroidcl install $p
+    done
+    for p in ${!installed[@]}; do
+        ${updated[$p]:-true} || fdroidcl upgrade $p
+    done
+}
+
+firefox-default-profile() {
+    key=Default value=1 section=$1
+    file=/p/c/subdir_files/.mozilla/firefox/profiles.ini
+    sed -ri "/^ *$key/d" "$file"
+    sed -ri "/ *\[$section\]/,/^ *\[[^]]+\]/{/^\s*$key[[:space:]=]/d};/ *\[$section\]/a $key=$value" "$file"
+}
+fdhome() { #firefox default home profile
+    firefox-default-profile Profile0
 }
 
-fastboot() { /a/opt/androidsdk/platform-tools/fastboot "$@"; }
+fdwork() {
+    firefox-default-profile Profile4
+}
 
 ff() {
     if type -P firefox &>/dev/null; then
@@ -577,6 +735,29 @@ feh() {
     command feh -FzZ "$@"
 }
 
+# mail related
+frozen() {
+    rm -rf /tmp/frozen
+    s mailq |gr frozen|awk '{print $3}' | while read -r id; do
+        s exim -Mvl $id
+        echo
+        s exim -Mvh $id
+        echo
+        s exim -Mvb $id
+        echo -e '\n\n##############################\n'
+    done | tee -a /tmp/frozen
+}
+frozenrm() {
+    local ids=()
+    while read -r line; do
+        printf '%s\n' "$line"
+        ids+=($(printf '%s\n' "$line" |gr frozen|awk '{print $3}'))
+    done < <(s mailq)
+    echo "sleeping for 2 in case you change your mind"
+    sleep 2
+    s exim -Mrm "${ids[@]}"
+}
+
 funce() {
     # like -e for functions. returns on error.
     # at the end of the function, disable with:
@@ -641,6 +822,10 @@ and works in older versions of git which did not have that."
     echo "${p%%/.git}"
 }
 
+gitian() {
+    git config user.email ian@iankelling.org
+}
+
 gmacs() {
     # quit will prompt if the program crashes.
     gdb -ex=r -ex=quit --args emacs "$@"; r;
@@ -704,7 +889,7 @@ hl() { # history limit. Write extra history to archive file.
 }
 
 hr() { # horizontal row. used to break up output
-    printf "$(tput setaf 5)█$(tput sgr0)%.0s" $(seq $COLUMNS)
+    printf "$(tput setaf 5)█$(tput sgr0)%.0s" $(seq ${COLUMNS:-60})
     echo
 }
 
@@ -737,7 +922,7 @@ ifn() {
     # insensitive find
     find -L . -not \( -name .svn -prune -o -name .git -prune \
          -o -name .hg -prune -o -name .editor-backups -prune \
-    -o -name .undo-tree-history -prune \) -iname "*$**" 2>/dev/null
+         -o -name .undo-tree-history -prune \) -iname "*$**" 2>/dev/null
 }
 
 
@@ -766,7 +951,15 @@ else
     }
 fi
 
+net-dev-info() {
+    e "lspci -nnk|gr -iA2 net"
+    lspci -nnk|gr -iA2 net
+    hr
+    e "s lshw -C network"
+    hr
+    s lshw -C network
 
+}
 
 istext() {
     grep -Il "" "$@" &>/dev/null
@@ -776,6 +969,11 @@ jtail() {
     journalctl -n 10000 -f "$@" | grep -Evi "^(\S+\s+){4}(sudo|sshd|cron)"
 }
 
+kff() { # keyboardio firmware flash
+    pushd /a/opt/sketches/Model01-Firmware
+    yes $'\n' | make flash
+    popd
+}
 
 l() {
     if [[ $PWD == /[iap] ]]; then
@@ -790,23 +988,26 @@ lcn() { locate -i "*$**"; }
 
 lld() { ll -d "$@"; }
 
-low() {  # make filenames all lowercase
-    local x y
-    for x in "$@"; do
-        y=$(tr "[A-Z]" "[a-z]" <<<"$x")
-        [[ $y != $x ]] && mv "$x" "$y"
+low() {  # make filenames lowercase, remove bad chars
+    local f new
+    for f in "$@"; do
+        new="${f,,}" # downcase
+        new="${new//[^[:alnum:]._-]/_}" # sub bad chars
+        new="${new#"${new%%[[:alnum:]]*}"}" # remove leading/trailing non-alnum
+        new="${new%"${new##*[[:alnum:]]}"}"
+        # remove bad underscores, like __ and _._
+        new=$(echo $new | sed -r 's/__+/_/g;s/_+([.-])|([.-])_+/\1/g')
+        safe_rename "$f" "$new" || return 1
     done
+    return 0
 }
 
-
-
-
 lower() { # make first letter of filenames lowercase.
     local x
     for x in "$@"; do
         if [[ ${x::1} == [A-Z] ]]; then
             y=$(tr "[A-Z]" "[a-z]" <<<"${x::1}")"${x:1}"
-            safe_rename "$x" "$y"
+            safe_rename "$x" "$y" || return 1
         fi
     done
 }
@@ -816,20 +1017,63 @@ k() { # history search
     grep -P --binary-files=text "$@" ${HISTFILE:-~/.bash_history}  | tail -n 80;
 }
 
+ks() { # history search
+    grep -P --binary-files=text "$@" ${HISTFILE:-~/.bash_history}  | uniq;
+}
+
 
 make-targets() {
     # show make targets, via http://stackoverflow.com/questions/3063507/list-goals-targets-in-gnu-make
     make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'
 }
 
+mbenable() {
+    mb=$1
+    dst=/m/4e/$1
+    src=/m/md/$1
+    set -x
+    mv -T $src $dst || { set +x; return 1; }
+    ln -s -T $dst $src
+    /a/exe/lnf /p/.mu ~
+    mu index --maildir=/m/4e
+    set +x
+}
+mbdisable() {
+    mb=$1
+    dst=/m/md/$1
+    src=/m/4e/$1
+    set -x
+    if [[ -L $dst ]]; then rm $dst; fi
+    mv -T $src $dst
+    set +x
+}
+
+mdt() {
+    markdown -o /tmp/mdtest.html "$1"
+    firefox /tmp/mdtest.html
+}
+
 
 mkc() {
     mkdir "$1"
     c "$1"
 }
 
+mkt() { # mkdir and touch file
+    local path="$1"
+    mkdir -p "$(dirname "$path")"
+    touch "$path"
+}
+
 mkdir() { command mkdir -p "$@"; }
 
+mo() { xset dpms force off; } # monitor off
+
+otp() {
+    oathtool --totp -b "$@" | xclip -selection clipboard
+}
+
+# pithosfly is broken due to bitrot.
 pithos() {
     cd /
     export PYTHONPATH=/a/opt/Pithosfly
@@ -887,13 +1131,7 @@ pick-trash() {
     done
 }
 
-postconfin() {
-    local MAPFILE
-    mapfile -t
-    local s
-    [[ $EUID == 0 ]] || s=s
-    $s postconf -ev "${MAPFILE[@]}"
-}
+ping8() { ping 8.8.8.8; }
 
 pub() {
     rld /a/h/_site/ li:/var/www/iankelling.org/html
@@ -902,6 +1140,25 @@ pub() {
 pubip() { curl -4s https://icanhazip.com; }
 whatismyip() { pubip; }
 
+pumpa() {
+    # fixes the menu bar in xmonad. this won\'t be needed when xmonad
+    # packages catches up on some changes in future (this is written in
+    # 4/2017)
+    #
+    # geekosaur: so you'll want to upgrade to xmonad 0.13 or else use a
+    # locally modified XMonad.Hooks.ManageDocks that doesn't set the
+    # work area; turns out it's impossible to set correctly if you are
+    # not a fully EWMH compliant desktop environment
+    #
+    # geekosaur: chrome shows one failure mode, qt/kde another, other
+    # gtk apps a third, ... I came up with a setting that works for me
+    # locally but apparently doesn't work for others, so we joined the
+    # other tiling window managers in giving up on setting it at all
+    #
+    xprop -root -remove _NET_WORKAREA
+    command pumpa &r
+}
+
 
 pwgen() {
     # -m = min length
@@ -965,6 +1222,25 @@ rlu() { # [OPTS] HOST PATH
     s rsync -rlpchviog --relative "${opts[@]}" "$path" "root@$host:/";
 }
 
+# only run on desktop. simpler to keep this on one system.
+r2eadd() { # usage: name url
+    # initial setup of rss2email:
+    # r2e new r2e@iankelling.org
+    # that initializes files, and sets default email.
+    # symlink to the config doesn't work, so I copied it to /p/c
+    # and then use cli option to specify explicit path.
+    # Only option changed from default config is to set
+    # force-from = True
+    #
+    # or else for a few feeds, the from address is set by the feed, and
+    # if I fail delivery, then I send a bounce message to that from
+    # address, which makes me be a spammer.
+
+    r2e add $1 "$2" $1@r2e.iankelling.org
+    # get up to date and don't send old entries now:
+    r2e run --no-send $1
+}
+r2e() { command r2e -d /p/c/rss2email.json -c /p/c/rss2email.cfg "$@"; }
 
 rspicy() { # usage: HOST DOMAIN
     # connect to spice vm remote host. use vspicy for local host
@@ -980,6 +1256,10 @@ EOF
     fi
 }
 
+rmstrips() {
+    ssh fencepost head -n 300 /gd/gnuorg/EventAndTravelInfo/rms-current-trips.txt
+}
+
 s() {
     # background
     # I use a function because otherwise we can't use in a script,
@@ -996,15 +1276,17 @@ s() {
     fi
 }
 
-safe_rename() {
+safe_rename() { # warn and don't rename if file exists.
+    # mv -n exists, but it's silent
     if [[ $# != 2 ]]; then
         echo safe_rename error: $# args, need 2 >2
         return 1
-    elif [[ $1 != $2 ]]; then
-        if [[ -e $2 ]]; then
-            echo Cannot rename "$1" to "$2" as it already exists.
+    fi
+    if [[ $1 != $2 ]]; then # yes, we want to silently ignore this
+        if [[ -e $2 || -L $2 ]]; then
+            echo "Cannot rename $1 to $2 as it already exists."
         else
-            mv "$1" "$2"
+            mv -vi "$1" "$2"
         fi
     fi
 }
@@ -1035,9 +1317,31 @@ ser() {
     fi
 }
 
+setini() { # set a value in a .ini style file
+    key="$1" value="$2" section="$3" file="$4"
+    if [[ -s $file ]]; then
+        sed -ri -f - "$file" <<EOF
+# remove existing keys
+/ *\[$section\]/,/^ *\[[^]]+\]/{/^\s*$key[[:space:]=]/d}
+# add key
+/^\s*\[$section\]/a $key=$value
+# from section to eof, do nothing
+/^\s*\[$section\]/,\$b
+# on the last line, if we haven't found section yet, add section and key
+\$a [$section]\\
+$key=$value
+EOF
+    else
+        cat >"$file" <<EOF
+[$section]
+$key=$value
+EOF
+    fi
+}
+
 sgo() { # service go
     service=$1
-    ser restart $service
+    ser restart $service || return 1
     if type -p systemctl &>/dev/null; then
         ser enable $service
     fi
@@ -1047,10 +1351,44 @@ sgo() { # service go
 shellck() {
     # 2086 = unquoted $var
     # 2046 = unquoted $(cmd)
-    # i had -x as an arg, but debian testing(stretch) doesn't support it
+    # i had -x as an arg, but debian testing(stretch) doesn\'t support it
     shellcheck -e 2086,2046,2068,2006,2119 "$@"
 }
 
+skaraoke() {
+    local tmp out
+    in="$1"
+    out=${2:-${1%.*}.sh}
+    tmp=$(mktemp -d)
+    script -t -c "mpv --no-config --no-resume-playback --no-terminal --no-audio-display '$1'" $tmp/typescript 2>$tmp/timing
+    # todo, the current sleep seems pretty good, but it
+    # would be nice to have an empirical measurement, or
+    # some better wait to sync up.
+    #
+    # note: --loop-file=no prevents it from hanging if you have that
+    # set to inf the mpv config.
+    # --loop=no prevents it from exit code 3 due to stdin if you
+    # had it set to inf in mpv config.
+    #
+    # args go to mpv, for example --volume=80, 50%
+    cat >$out <<EOFOUTER
+#!/bin/bash
+trap "trap - TERM && kill 0" INT TERM ERR; set -e
+( sleep .2; scriptreplay <( cat <<'EOF'
+$(cat $tmp/timing)
+EOF
+) <( cat <<'EOF'
+$(cat $tmp/typescript)
+EOF
+))&
+base64 -d - <<'EOF'| mpv --loop=no --loop-file=no --no-terminal --no-audio-display "\$@" -
+$(base64 "$1")
+EOF
+kill 0
+EOFOUTER
+    rm -r $tmp
+    chmod +x $out
+}
 
 slog() {
     # log with script. timing is $1.t and script is $1.s
@@ -1079,6 +1417,10 @@ splay() { # script replay
     scriptreplay "$1.t" "$1.s"
 }
 
+spend() {
+    s systemctl suspend
+}
+
 sr() {
     # sudo redo. be aware, this command may not work right on strange distros or earlier software
     if [[ $# == 0 ]]; then
@@ -1098,6 +1440,19 @@ srun() {
     ssh $1 /tmp/${2##*/} "${@:2}"
 }
 
+sss() { # ssh solo
+    ssh -oControlMaster=no -oControlPath=/ "$@"
+}
+ssk() {
+    local -a opts=()
+    while [[ $1 == -* ]]; do
+        opts+=("$1")
+        shift
+    done
+    m pkill -f "^ssh: /tmp/ssh_mux_${USER}_${1#*@}_22_"
+    m ssh "${opts[@]}" "$@"
+}
+
 swap() {
     local tmp
     tmp=$(mktemp)
@@ -1117,85 +1472,142 @@ t() {
             fi
         done
         [[ ! ${args[@]} ]] || trash-put "${args[@]}"
-    else
-        rm -rf "$@"
-    fi
-}
-
-
-tclock() {
-    clear
-    date +%l:%_M
-    len=60
-    # this goes to full width
-    #len=${1:-$((COLUMNS -7))}
-    x=1
-    while true; do
-        if (( x == len )); then
-            end=true
-            d="$(date +%l:%_M)   "
-        else
-            end=false
-            d=$(date +%l:%M:%_S)
-        fi
-        echo -en "\r"
-        echo -n "$d"
-        for ((i=0; i<x; i++)); do
-            if (( i % 6 )); then
-                echo -n _
-            else
-                echo -n .
-            fi
-        done
-        if $end; then
-            echo
-            x=1
+                           else
+                               rm -rf "$@"
+                          fi
+}
+
+
+ tclock() {
+     clear
+     date +%l:%_M
+     len=60
+     # this goes to full width
+     #len=${1:-$((COLUMNS -7))}
+     x=1
+     while true; do
+         if (( x == len )); then
+             end=true
+             d="$(date +%l:%_M)   "
+         else
+             end=false
+             d=$(date +%l:%M:%_S)
+         fi
+         echo -en "\r"
+         echo -n "$d"
+         for ((i=0; i<x; i++)); do
+             if (( i % 6 )); then
+                 echo -n _
+             else
+                 echo -n .
+             fi
+         done
+         if $end; then
+             echo
+             x=1
+         else
+             x=$((x+1))
+         fi
+         sleep 5
+     done
+ }
+
+
+ te() {
+     # test existence / exists
+     local ret=0
+     for x in "$@"; do
+         [[ -e "$x" || -L "$x" ]] || ret=1
+     done
+     return $ret
+ }
+
+ # mail related
+ testmail() {
+     declare -gi _seq; _seq+=1
+     echo "test body" | m mail -s "test mail from $HOSTNAME, $_seq" "${@:-root@localhost}"
+     # for testing to send from an external address, you can do for example
+     # -aFrom:ian@iank.bid web-6fnbs@mail-tester.com
+     # note in exim, you can retry a deferred message
+     # s exim -M MSG_ID
+     # MSG_ID is in /var/log/exim4/mainlog, looks like 1ccdnD-0001nh-EN
+ }
+
+ # to test sieve, use below command. for fsf mail, see fsf-get-mail script.
+ # make modifications, then copy to live file, use -eW to actually modify mailbox
+ # cp /p/c/subdir_files/sieve/personal{test,}.sieve; testsievelist -eW INBOX
+ #
+ # Another option is to use sieve-test SCRIPT MAIL_FILE. note,
+ # sieve-test doesn't know about envelopes, I'm not sure if sieve-filter does.
+
+ # sieve with output filter. arg is mailbox, like INBOX.
+ # This depends on dovecot conf, notably mail_location in /etc/dovecot/conf.d/10-mail.conf
+
+ testsievelist() {
+     sieve-filter ~/sieve/maintest.sieve "$@" >/tmp/testsieve.log 2> >(tail) && sed -rn '/^Performed actions:/{n;n;p}' /tmp/testsieve.log | sort -u
+ }
+
+
+ # mail related
+ # plain sieve
+ testsieve() {
+     sieve-filter ~/sieve/main.sieve "$@"
+ }
+
+ # mail related
+ testexim() {
+     # testmail above calls sendmail, which is a link to exim/postfix.
+     # it's docs don't say a way of adding an argument
+     # to sendmail to turn on debug output. We could make a wrapper, but
+     # that is a pain. Exim debug args are documented here:
+     # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
+     #
+     # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-building_and_installing_exim.html
+     # note, for exim daemon, you can turn on debug options by
+     # adding -d, etc to COMMONOPTIONS in
+     # /etc/default/exim4
+     # for testing external mail, you need the to address as final cmdline arg
+     exim -d+tls -t <<'EOF'
+From: root@frodo.lan
+To: ian@mail.iankelling.org
+Subject: Testing Exim
+
+This is a test message.
+EOF
+ }
+
+ tm() {
+     # timer in minutes
+     # --no-config
+     (sleep $(calc "$@ * 60") && mpv --no-config --volume 50 /a/bin/data/alarm.mp3) > /dev/null 2>&1 &
+ }
+
+ trg() { transmission-remote-gtk&r; }
+ trc() {
+     # example, set global upload limit to 100 kilobytes:
+     # trc -u 100
+     TR_AUTH=":$(jq -r .profiles[0].password ~/.config/transmission-remote-gtk/config.json)" transmission-remote transmission.lan -ne "$@"
+ }
+
+
+ tu() {
+     local s;
+     local dir="$(dirname "$1")"
+     if [[ -e $1 && ! -w $1 || ! -w $(dirname "$1") ]]; then
+         s=s;
+     fi
+     $s teeu "$@"
+ }
+
+ tx() { # toggle set -x, and the prompt so it doesn't spam
+        if [[ $- == *x* ]]; then
+            set +x
+            PROMPT_COMMAND=prompt-command
         else
-            x=$((x+1))
+            unset PROMPT_COMMAND
+            PS1="\w \$ "
+            set -x
         fi
-        sleep 5
-    done
-}
-
-
-te() {
-    # test existence / exists
-    local ret=0
-    for x in "$@"; do
-        [[ -e "$x" || -L "$x" ]] || ret=1
-    done
-    return $ret
-}
-
-testmail() {
-    declare -gi _seq; _seq+=1
-    echo "test body" | m mail -s "test mail from $HOSTNAME, $_seq" "${1:-root@localhost}"
-}
-
-tm() {
-    # timer in minutes
-    (sleep $(calc "$@ * 60") && mpv --volume 50 /a/bin/data/alarm.mp3 --loop=no) > /dev/null 2>&1 &
-}
-
-
-tu() {
-    local s;
-    local dir="$(dirname "$1")"
-    if [[ -e $1 && ! -w $1 || ! -w $(dirname "$1") ]]; then
-        s=s;
-    fi
-    $s teeu "$@"
-}
-
-tx() { # toggle set -x, and the prompt so it doesn't spam
-    if [[ $- == *x* ]]; then
-        set +x
-        PROMPT_COMMAND=prompt_command
-    else
-        unset PROMPT_COMMAND
-        PS1="\w \$ "
-        set -x
-    fi
 }
 
 psnetns() {
@@ -1215,32 +1627,16 @@ m() { printf "%s\n" "$*";  "$@"; }
 
 
 vpncmd() {
-    m s nsenter -t $(pgrep -f "/usr/sbin/openvpn --suppress-timestamps --nobind --config /etc/openvpn/client/client.conf") -n -m "$@"
+    m s nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/client/client.conf") -n -m "$@"
 }
 vpnf() {
-    vpncmd gksudo -u ian firefox &r
+    vpncmd gksudo -u ian "firefox -no-remote -P firefox-main-profile" &r
 }
 vpnbash() {
     vpncmd bash
 }
 
 
-trg() { transmission-remote-gtk&r; }
-
-# transmission() {
-#     local pid=$(cat /var/lib/transmission-daemon/transmission-daemon.pid)
-#     if [[ $pid && -e /proc/$pid ]]; then
-#         echo "noop. already running."
-#         return
-#     fi
-
-#     local NAME=transmission-daemon
-#     local DAEMON=/usr/bin/$NAME
-#     local duser=debian-transmission
-
-#     [ -e /etc/default/$NAME ] && . /etc/default/$NAME
-#     s ip netns exec vpn sudo -u $duser ionice -c 3 nice -n 19 $DAEMON $OPTIONS
-# }
 
 virshrm() {
     for x in "$@"; do virsh destroy "$x"; virsh undefine "$x"; done
@@ -1266,14 +1662,33 @@ vmunshare() {
     vm-set-listen $1 127.0.0.1
 }
 
+
 vpn() {
-    s systemctl start openvpn@client&
-    journalctl --unit=openvpn@client -f -n0
-}
+    if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
+        local vpn_service=openvpn-client
+    else
+        local vpn_service=openvpn
+    fi
 
+    [[ $1 ]] || { echo need arg; return 1; }
+    journalctl --unit=$vpn_service@$1 -f -n0 &
+    s systemctl start $vpn_service@$1
+    # sometimes the ask-password agent does not work and needs a delay.
+    sleep .5
+    # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=779240
+    # noticed around 8-2017 after update from around stretch release
+    # on debian testing, even though the bug is much older.
+    s systemd-tty-ask-password-agent
+}
 
 vpnoff() {
-    s systemctl stop openvpn@client
+    [[ $1 ]] || { echo need arg; return 1; }
+    if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
+        local vpn_service=openvpn-client
+    else
+        local vpn_service=openvpn
+    fi
+    s systemctl stop $vpn_service@$1
 }
 
 
@@ -1291,13 +1706,49 @@ vspicy() { # usage: VIRSH_DOMAIN
 }
 
 
-whatismyip() { curl ipecho.net/plain ; echo; }
+wtr() { curl wttr.in/boston; }
 
+xl() {
+    if pgrep gnome-screensav &>/dev/null; then
+    # this command actually starts gnome-screensaver if it isn't running.
+    # lololol, what crap
+    gnome-screensaver-command --exit &>/dev/null
+    fi
+    mate-screensaver-command --exit &>/dev/null
+    if ! pidof xscreensaver; then
+        pushd /
+        xscreensaver &
+        popd
+        # 1 was not long enough
+        sleep 3
+    fi
+    xscreensaver-command -activate
+}
 
 #############################
 ######### misc stuff ########
 #############################
 
+# from curl cheat.sh/:bash_completion
+_cheatsh_complete_curl()
+{
+    local cur prev opts
+    _get_comp_words_by_ref -n : cur
+
+    COMPREPLY=()
+    #cur="${COMP_WORDS[COMP_CWORD]}"
+    prev="${COMP_WORDS[COMP_CWORD-1]}"
+    opts="$(curl -s cheat.sh/:list | sed s@^@cheat.sh/@)"
+
+    if [[ ${cur} == cheat.sh/* ]] ; then
+       COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
+       __ltrim_colon_completions "$cur"
+        return 0
+    fi
+}
+complete -F _cheatsh_complete_curl curl
+
+
 if [[ $- == *i* ]]; then
     # commands to run when bash exits normally
     trap "hl" EXIT
@@ -1408,22 +1859,15 @@ if [[ $- == *i* ]]; then
         PS1="\h $PS1"
     fi
 
-    prompt_command() {
+
+
+
+    prompt-command() {
         local return=$? # this MUST COME FIRST
         local psc pst ps_char ps_color stale_subvol
         unset IFS
         history -a # save history
 
-        # for titlebar
-        if [[ ! $DESKTOP_SESSION == xmonad && $TERM == *(screen*|xterm*|rxvt*) ]]; then
-            # from the screen man page
-            if [[ $TERM == screen* ]]; then
-                local title_escape="\033]..2;"
-            else
-                local title_escape="\033]0;"
-            fi
-           echo -ne "$title_escape${PWD/#$HOME/~}  $USER@$HOSTNAME\007"
-       fi
 
 
         case $return in
@@ -1453,9 +1897,70 @@ if [[ $- == *i* ]]; then
         # emacs completion doesn't like the git prompt atm, so disabling it.
         #PS1="${PS1%"${PS1#*[wW]}"}$(__git_ps1 ' (%s)') \[$ps_color\]$ps_char\[$(get_term_color nocolor)\] "
     }
-    PROMPT_COMMAND=prompt_command
+    PROMPT_COMMAND=prompt-command
+
+    settitle () {
+        if [[ $TERM == screen* ]]; then
+            local title_escape="\033]..2;"
+        else
+            local title_escape="\033]0;"
+        fi
+        if [[ $* != prompt-command ]]; then
+           echo -ne "$title_escape$USER@$HOSTNAME ${PWD/#$HOME/~} $*\007"
+        fi
+    }
+
+    # for titlebar
+    # condition from the screen man page i think
+    if [[ $TERM == *(screen*|xterm*|rxvt*) ]]; then
+        trap 'settitle "$BASH_COMMAND"' DEBUG
+    else
+        trap DEBUG
+    fi
+
 fi
 
+reset-konsole() {
+    # we also have a file in /a/c/...konsole...
+    local f=$HOME/.config/konsolerc
+    setini DefaultProfile profileian.profile "Desktop Entry" $f
+    setini Favorites profileian.profile "Favorite Profiles" $f
+    setini ShowMenuBarByDefault false KonsoleWindow $f
+    setini TabBarPosition Top TabBar $f
+}
+
+reset-sakura() {
+    while read k v; do
+        setini $k $v sakura /a/c/subdir_files/.config/sakura/sakura.conf
+    done <<'EOF'
+colorset1_back rgb(33,37,39
+less_questions true
+audible_bell No
+visible_bell No
+disable_numbered_tabswitch true
+scroll_lines 10000000
+scrollbar true
+EOF
+}
+
+reset-xscreensaver() {
+    # except for spash, i set these by setting gui options in
+    # xscreensaver-command -demo
+    # then finding the corresponding option in .xscreensaver
+    # spash, i happened to notice in .xscreensaver
+    cat > /home/iank/.xscreensaver <<'EOF'
+mode:          blank
+dpmsEnabled:   True
+dpmsStandby:   0:01:00
+dpmsSuspend:   0:01:00
+dpmsOff:       0:02:00
+timeout:       0:01:00
+lock:           True
+lockTimeout:   0:02:00
+splash:                False
+EOF
+
+}
 
 
 ###########################################
@@ -1494,16 +1999,16 @@ fi
 # based on warning from rvmsudo
 export rvmsudo_secure_path=1
 
-# for other script I wrote
-#export ACME_TINY_PATH=/a/opt/acme-tiny
-export ACME_TINY_WRAPPER_CERT_DIR=/p/c/machine_specific/$HOSTNAME/webservercerts
-
 if [[ -s "/usr/local/rvm/scripts/rvm" ]]; then
     source "/usr/local/rvm/scripts/rvm"
 elif [[ -s $HOME/.rvm/scripts/rvm ]]; then
     source $HOME/.rvm/scripts/rvm
 fi
 
+export GOPATH=$HOME/go
+path_add $GOPATH/bin
+
+export ARDUINO_PATH=/a/opt/Arduino/build/linux/work
 
 path_add --end ~/.npm-global