#!/bin/bash

# If not running interactively, don't do anything
# [[ "$-" != *i* ]] && echo "\"$-\" != *i*" && exit 34

export EDITOR='emacs -nw'
which code >/dev/null 2>&1 && export EDITOR='code --wait'
export REACT_EDITOR='code'
export LANG="en_US.UTF-8"
export LC_ALL=$LANG
export LC_COLLATE="C" # case insensitive Nautulis filename sorting
export DOCKER_HOST="unix:///run/user/$(id -u)/docker.sock"
export GOPATH=~/.local/share/go
export PNPM_HOME="/home/dys/.local/share/pnpm"
export NVM_DIR="$HOME/.nvm"

export BUN_INSTALL="$HOME/.bun"
export ANDROID_HOME="$HOME/Android/Sdk"
export ANDROID_SDK_ROOT="$ANDROID_HOME"
export ANDROID_NDK_HOME="$ANDROID_SDK_ROOT/ndk/$(ls $ANDROID_SDK_ROOT/ndk/ -1 --color=never 2> /dev/null | tail -n1 | tr -d " \n")"

export RSYNC_RSH=ssh
export CVS_RSH=ssh

for path in \
 ~/.pub-cache/bin/ \
 /usr/local/bin/ \
 /opt/local/bin/ \
 ~/.cargo/bin/ \
 ~/.radicle/bin/ \
 ~/.rbenv/bin/ \
 ~/.deno/bin/ \
 $ANDROID_HOME/tools \
 $ANDROID_HOME/tools/bin \
 $BUN_INSTALL/bin/ \
 $PNPM_HOME \
 ~/.local/bin/ \
 ~/.../bin/ \
 ~/bin/; do
  [ -d "$path" ] && export PATH="$path:$PATH"
done

# which nvm > /dev/null 2>&1 && export PATH="$(dirname $(nvm which current)):$PATH"
# if which nodenv > /dev/null 2>&1; then
#   eval "$(nodenv init - bash)"
#   nodenv global > /dev/null
# fi
which fnm > /dev/null && eval "$(fnm env --use-on-cd)"

for path in \
  $(which npm > /dev/null && npm list -g | head -n1) \
  $(which yarn > /dev/null && yarn global bin)
  do
  [ -d "$path" ] && export PATH="$path:$PATH"
done


__conda_setup="$(~/.local/anaconda3/bin/conda shell.bash hook 2> /dev/null)"
if [ $? -eq 0 ]; then
  eval "$__conda_setup"
fi
unset __conda_setup

for path in /var/lib/flatpak/exports/share ~/.local/share/flatpak/exports/share; do
  [ -d "$path" ] && export XDG_DATA_DIRS="$path:$XDG_DATA_DIRS"
done

if [ "$PS1" ]; then
  host=$(hostname)
  PS1='\n\u@\h\[\033[1;35m\]:\[\033[0m\]\w\[\033[1;33m\]\$\[\033[0m\] '
  # PS1='$(stty echo)\n\[\033[1;33m\]@\[\033[0m\]$host\[\033[35m\]\$\[\033[0m\]$(
  #   dir=$(pwd)
  #   [ "$dir" != "${dir#$(echo ~)}" ] && dir="~${dir#$(echo ~)}"
  #   [ "$dir" != "${dir##*/...}" ] && dir="\[\033[34m\]∅\[\033[0m\]${dir##*/...}"
  #   echo $dir
  #   )\[\033[1;33m\]:\[\033[0m\] '
fi

# To remove language selection menus from windows in Solaris
export XIM="htt"
export GTK_IM_MODULE=iiim
export XMODIFIERS="@im=${XIM}"

# Make bash append rather than overwrite the history on disk
shopt -s histappend

# don't put duplicate lines in the history. See bash(1) for more options
HISTCONTROL=$HISTCONTROL${HISTCONTROL+,}ignoredups

# Check the window size after each command and update LINES and COLUMNS.
shopt -s checkwinsize

# Includes filenames beginning with '.' in pathname expansion.
shopt -s dotglob

# ** matches one or more directories
# ToDo: Reenable with error checking when not available
shopt -s globstar

[ -r ".../config/inputrc" ] && export INPUTRC=".../config/inputrc"

bind 'set match-hidden-files off' # Ignore hidden files in tab completion
bind 'set colored-stats on'

for completion in \
 /etc/bash_completion.d/git-prompt \
 /usr/share/bash-completion/completions/git \
 ~/.../linux/distro/ubuntu/shell/config/bash \
 ~/.config/tabtab/__tabtab.bash \
 ~/bin/google-cloud-sdk/path.bash.inc \
 ~/bin/google-cloud-sdk/completion.bash.inc \
 ~/.cargo/env \
 ~/.profile_mycroft; do
  [ -f $completion ] && source $completion
done

which npm > /dev/null 2>&1 && source <(npm completion)
which pack > /dev/null 2>&1 && source "$(pack completion)"
which starship > /dev/null 2>&1 && eval "$(starship init bash)"

if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
  source /etc/bash_completion
fi

complete -o default code
complete -o default jq

[ -e /usr/bin/terraform ] && complete -C /usr/bin/terraform terraform

[ -e ~/bin/export-esp.sh ] && source ~/bin/export-esp.sh
[ -e ~/bin/bash-preexec.sh ] && source ~/bin/bash-preexec.sh

which pyenv > /dev/null 2>&1 && eval "$(pyenv init -)"
which dircolors > /dev/null 2>&1 && eval $(dircolors)
command -v direnv > /dev/null 2>&1 && eval "$(direnv hook bash)"
which kubectl > /dev/null 2>&1 && source <(kubectl completion bash)
which rbenv > /dev/null 2>&1 && eval "$(rbenv init -)"
which ipfs > /dev/null 2>&1 && eval "$(ipfs commands completion bash)"

[ -z "$PS1" ] || (
  which fortune >/dev/null 2>&1 && (
    which notify-send >/dev/null 2>&1 && (
      fortune=$(fortune | sed -z 's/\n/ /g;s/[ \t][ \t]*/ /g')
      notify-send -t 1000 -u low -i gtk-dialog-info Fortune "$fortune"
    ) || (
      setterm -underline on
      fortune
      setterm -underline off
    )
  )
)

[ -r ~/.../config/muttrc ] && alias mutt="mutt -F ~/.../config/muttrc"

alias rm='rm -v'

alias vram="glxinfo | grep -E '(video|available) memory'"
alias dbus-gui=d-feet
alias which-pkg='dpkg -S'
alias pw-graph=qpwgraph

alias search-pkgs='find -name package.json -not -path "**/node_modules/**" | xargs grep --color=always'

alias nr="npm run"
alias ni="npm install"
alias recent="last -ad | head -n 15"
alias mailq="sudo mailq -Ac; sudo mailq"
alias putmail="sudo /usr/sbin/sendmail -q"

alias sync-backup="sudo rsync --archive --acls \
   --info=progress2,stats3,copy,del,symsafe,backup,name2,skip2,misc2 \
   --delete --progress --stats \
   --xattrs --atimes --hard-links \
   --exclude={'/dev','/proc','/sys','/tmp','/run','/mnt','/media','/snap','/lost+found'} \
   --exclude=$HOME/backup/ --exclude=$HOME/ssd/ / $HOME/backup"
alias copypart='rsync -axHAWXS --numeric-ids --info=progress2'

alias days="date=\$(date +%Y/%m/%d); \
            passed=\$(perl $PROG_DIR/bin/days.pl 2003/6/24 \$date); \
            left=\$(perl $PROG_DIR/bin/days.pl \$date 2005/9/16); \
            percent=\$(( \$passed * 10000 / (\$passed + \$left) )); \
            percent=\${percent:0:\$(( \${#percent} - 2 ))}.\${percent#??}; \
            echo \$date - you have been here \$passed days and have \$left left \(\$percent%\)"

alias monitorsleep="sleep 1 && xset dpms force off"

export __HASHDIR=".../hashes/"
export LOCAL="$__HASHDIR"
ARGS="--rsh=ssh --partial --progress --verbose --recursive --archive --compress"

alias hashbins="find \( -name jpg -or -name png -or -name gif -or -name odp -or -name mpeg -or -name avi -or -name webm -or -name ttf \) -print0 | xargs -0 lnhash"
alias pushhashes="eval rsync $ARGS \"\$LOCAL\" \"\$REMOTE:\$__HASHDIR\""
alias pullhashes="rsync $ARGS \"\$REMOTE:\$__HASHDIR\" \"\$LOCAL\""

alias print="eval echo \$OUT"

alias randkey="head -n 2048 /dev/urandom | sha256sum | cut -f1 -d' '"
alias gen128key="openssl ecparam -name secp128r1 -genkey -noout | openssl ec -text -noout"
alias gen256key="openssl ecparam -name secp256k1 -genkey -noout | openssl ec -text -noout"
alias 128pubkey="gen128key | grep pub -A 3 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^04//'"
alias 128privkey="gen128key | grep priv -A 2 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^00//'"

alias q='popd'
function p() {
  if [[ -z "$*" && -d ~/... ]]; then
    pushd ~/...
  else
    pushd "$@"
  fi
}
complete -o nospace -F _cd p
function pp() {
  popd
  pushd "$PWD"
  cd "$@"
}

[ -d ~/bin ] && export PATH=~/bin:"$PATH" && export GOBIN=~/bin

for JDK in /opt/ibm/java-x86_64-80/jre/bin/ \
 /usr/lib/kaffe/bin/ \
 /usr/java/jdk*/bin/ \
 /usr/lib/jdk*/bin/ \
 '/cygdrive/c/Program Files/Java/jdk'*/bin/; do
  if [[ -e "${JDK}java" || -e "${JDK}java.exe" ]]; then
    export PATH="$JDK:$PATH"
    break
  fi
done
export JAVACMD=$(which java)

alias pauseamarok="dcop --user $USER amarok player playPause"

alias disable-ipv6='sudo sysctl \
-w net.ipv6.conf.lo.disable_ipv6=1 \
-w net.ipv6.conf.all.disable_ipv6=1 \
-w net.ipv6.conf.default.disable_ipv6=1'
alias clip='xclip -sel clip'

alias hornetlog='journalctl -u hornet.service -f'
alias lotuslog='journalctl -u lotus-daemon'

# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
alias less='less -R'

alias cpu-version=cpufetch
alias ubuntu-version='lsb_release -a'
alias ubuntu-version=neofetch

# Power down the monitor and unpause Amarok for exiting music on a blog post
function timeblog() {
  TIME=${1:-60} # Number of seconds to wait
  sleep 1 && xset dpms force off && sleep $TIME && qdbus org.kde.amarok /Player org.freedesktop.MediaPlayer.Play
}

alias xscreensaver-disable='xscreensaver-command -restart'
alias ssaver='xscreensaver-command -activate'

function suspend() {
  (sudo sleep 30 && sudo sh -c 'echo -n S3 > /sys/power/state') &
  echo "Suspending in 30 seconds"
}

function settitle() {
  printf "\033]0;$*\007"
}
alias st='settitle'

alias edit="$EDITOR" # Mistype: 8/12/2009

alias monerod="$HOME/bin/monero/monerod --data-dir=$HOME/ssd/Monero\\ blockchain/"

alias sandbox-permissions='flatpak run com.github.tchx84.Flatseal'
alias gaupol='flatpak run io.otsaloma.gaupol'
alias shortwave='flatpak run de.haeckerfelix.Shortwave'
alias opendrive='flatpak run io.github.liberodark.OpenDrive'
alias tor='flatpak run com.github.micahflee.torbrowser-launcher'
alias wezterm='flatpak run org.wezfurlong.wezterm'
# alias inkscape='flatpak run org.inkscape.Inkscape'
alias pw-helvum='flatpak run org.pipewire.Helvum'
alias pw-coppwr='flatpak run io.github.dimtpap.coppwr'
alias pw-effects='flatpak run com.github.wwmm.easyeffects'
alias vpup='flatpak run pro.vpup.vpuppr'
alias brave='brave-browser'
CURSORPROG="$(/bin/ls ~/bin/cursor* -rt 2> /dev/null | tail -n1)"
[ ! -z "$CURSORPROG" ] && alias csr="$CURSORPROG"

alias i2pup='i2prouter start'
alias i2pdown='i2prouter stop'

alias restart-network='sudo systemctl restart NetworkManager.service'

function fixvideo() {
  if [[ -z "$1" || -z "$2" ]]; then
    echo "Usage: fixvideo <same camera reference video> <broken video>"
    return 5
  fi
  untrunc -s "$1" "$2"
}

alias cb='xclip -selection c'

alias psql-start='sudo systemctl start postgresql.service'
alias psql-stop='sudo systemctl stop postgresql.service'

function findnewer() { find -newermt "$*"; }
function findnnm() { find -name node_modules -prune -o -name "$*" -print; }
function grepnnm() { rg --iglob '!node_modules' "$*"; }

alias iotaseed='cat /dev/urandom | tr -dc A-Z9 | head -c${1:-81}'
alias randhex='cat /dev/urandom | tr -dc A-F0-9 | head -c${1:-32}'

function duoftype() { 
  find -iname "*.$1" -print0 | du --files0-from - -csh
}

function zview() {
  zlib-flate -uncompress <"$*"
}

function keccak() {
  echo "Input: '$*'"
  echo -n "$*" | rhash --sha3-256 -
}

alias nordc='nordvpn connect'
alias nordd='nordvpn disconnect'
alias nordwlport='nordvpn whitelist add port'
alias nordset='nordvpn settings'
alias nordstat='nordvpn status'

alias debugchrome='google-chrome --remote-debugging-port=9222'

alias servehere='ruby -run -e httpd . -p 9999'
alias netuse='sudo ss -l -A inet -p'

alias ddf='df -h | grep "\\(sd\\|nvme\\)"'

alias bat='batcat'
alias fd='fdfind --color=always'
alias lls='ls -l'
alias listio='iotop -oPa -d 2'
alias listurls='katana -u'
alias meminfo='sudo dmidecode -t memory'
alias ipinfo='netlas host'

alias idg='ipfs dag get'
alias ils='ipfs ls'
alias v0cid='ipfs cid format -v 0'
alias v1cid='ipfs cid format -v 1'

# MetaGame Kubernetes debugging commands
alias gcauth='gcloud auth login'
alias gccreds='gcloud container clusters get-credentials metagame-cluster --region us-east4 --project metagame-thegame'
alias mgnamespaces='kubectl get namespaces'
alias mgcpods='kubectl get pods --namespace=ceramic'
alias mgclogs='kubectl logs ceramic-0 -n ceramic'
alias mgclogsfollow='kubectl logs ceramic-0 -n ceramic -f'
alias mgclogsprev='kubectl logs ceramic-0 -n ceramic --previous'
alias mgcservices='kubectl get services --namespace=ceramic'
alias mgcall='kubectl get all -nceramic'
alias mgcpod='kubectl describe pods ceramic-0 -nceramic'
alias mgnodes='kubectl get nodes'

# commands for finding lingering debug statements in Rails apps
FIT_EXPR='\sfit\s|\sfocus:\s*true\s|\sbinding.pry[[:space:]]|^\+\+\+'
function f() {
  git status -v | egrep '^\+' | egrep "$FIT_EXPR"
  git diff | egrep '^\+' | egrep "$FIT_EXPR"
}
function ff() {
  find -type f -name \*rb -print0 | xargs -0 egrep -e $EXPR -v --color
}
alias fp="gg -E '\sp\$|\sp\s|\sp\;|binding\.pry|\sspecify\!' -- '*.rb'"
alias spk='rspec --tag focus --tag ~focus'

alias sysstart='systemctl list-units --type service'

alias dname='lsb_release -a'

alias ...='p ~/...'

alias fortune='fortune -a'

alias gdec='gpg --decrypt'
alias mykeys='gpg --list-secret-keys --keyid-format=long'
function mykey {
  [ -z "$1" ] && echo "Usage: mykey <email address>" && return 1
  gpg --export --armor "$1"
}

alias ybyd='yarn build && yarn deploy'

alias g='grep --color'

function eb() { $EDITOR ~/.bashrc && source ~/.bashrc; }
function tb() { which bat > /dev/null && bat ~/.bashrc || less ~/.bashrc; }
alias rb='source ~/.bashrc' # reload bash

alias wins="wmctrl -l"

alias 25pwin="sh -c 'xprop -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY $(printf 0x%x $((0xffffffff * 25 / 100)))'"
alias 50pwin="sh -c 'xprop -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY $(printf 0x%x $((0xffffffff * 50 / 100)))'"
alias 75pwin="sh -c 'xprop -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY $(printf 0x%x $((0xffffffff * 75 / 100)))'"
alias 80pwin="sh -c 'xprop -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY $(printf 0x%x $((0xffffffff * 80 / 100)))'"
alias 90pwin="sh -c 'xprop -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY $(printf 0x%x $((0xffffffff * 90 / 100)))'"
alias 95pwin="sh -c 'xprop -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY $(printf 0x%x $((0xffffffff * 95 / 100)))'"
alias 99pwin="sh -c 'xprop -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY $(printf 0x%x $((0xffffffff * 99 / 100)))'"
alias opwin="sh -c 'xprop -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY $(printf 0x%x $((0xffffffff)))'"
alias 100pwin='opwin'

alias pin='ipfs pin add'
alias unpin='ipfs pin rm'
alias unpinall='ipfs pin ls -q --type recursive | xargs ipfs pin rm'
alias ipnskey='ipfs key gen --type=rsa --size=2048'
function ipnspub() {
  if [ -z "$1" ]; then
    echo "Usage: ipnspub <key name> <hash>"
    return 2
  fi
  ipfs name publish --key=$1 "$2"
}

# Always create intermediate directories
alias mkdir="mkdir -p"

function x2wav() { ffmpeg -i "$1" -c:a pcm_s16le -ar 16000 "${1%.*}.wav"; }
alias img2svg=vtrace
alias ttf2woff=sfnt2woff
alias otf2woff=sfnt2woff
function 2french() { cat "$*" | trans :fr; }
alias fffilters='ffmpeg -filters'
alias framecount='ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0'

alias xmlpp="xmllint --format"

# Verify a json file
function json() {
  for file in "$@"; do
    echo "Checking: $file"
    cat "$file" | python -mjson.tool
  done
}

alias findbiggitfiles="git ls-files -t \$(find . -type f -size +1M -print0 | xargs -0)"
alias lssize="find . -type f | cut -d/ -f2 | sort | uniq -c"
alias ka='killall'
alias logout=gnome-session-quit
alias rec=gnome-sound-recorder

function commit-for-chrissake() {
  fortune="$(fortune -s)"
  git commit -am "${*:-$fortune}"
}
function t() {
  if [ -z "$*" ]; then
    git commit -S -a
  else
    echo "Commit: $*"
    git commit -S -am "$*"
  fi
}
function tv() { git commit --no-verify -S -am "$*"; }
function mit() {

  if [ -z "$*" ]; then
    git commit -S
  else
    allfiles=1
    for file in "$@"; do
      if [ ! -f "$file" ]; then
        allfiles=0
        break
      fi
    done
    if [ $allfiles -eq 1 ]; then
      git commit -S -a "$@"
    else
      git commit -S -m "$*"
    fi
  fi
}
function t-() { git commit --amend -S -m "$*"; }

alias m='git merge'
__git_complete m _git_merge
alias u='git reset --soft HEAD~1'
alias hardr='git reset --hard'
alias undostashpop='git reset --merge'
alias pulsemixer=pavucontrol
alias pulsemods='pactl list modules short'
alias pulsesinks='pactl list sinks short'
alias pulsesources='pactl list sources short'

function gg() { git grep --line-number "$@" -- ':(exclude).yarn/**'; }
alias fetch='git fetch'
alias pull='git pull --allow-unrelated-histories'
__git_complete pull _git_pull
alias gp='git push'
__git_complete gp _git_push
alias aa='git add .'
alias co='git checkout'
__git_complete co _git_checkout
alias mb='git checkout -b'
alias gs='git stash --include-untracked'
alias sp='git stash pop'
alias ggraph='git log --decorate --graph --oneline --all'
alias ggraph="git log --all --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%ci) %C(bold blue)<%an>%Creset'"
alias clean='git clean'
alias s='git -c color.status=always status | less -REX'
alias b='git branch'
__git_complete b _git_branch
function d() {
  (
    git -c color.ui=always status -v
    git -c color.ui=always diff --staged
    git -c color.ui=always diff
    while IFS= read -r -d $'\0' file; do
      isutf8 "$file" 2>&1 >/dev/null
      IS_TEXT=$?
      if [ -f "$file" ]; then
        echo -e "\x1B[0;31mUntracked:\x1B[0m \x1B[1;33m$file\x1B[0m"
        if [ $IS_TEXT -eq 0 ]; then
          awk '{ print "  " $0 }' "$file"
        else
          echo -e "  \x1B[1;35mNot Printing Binary…\x1B[0m"
        fi
      fi
    done < <(git ls-files --others --exclude-standard -z)
  ) | bat
}
alias l='git log -p'
alias lf='git log --name-status'

alias ds='docker stop'
function dconnect() {
  if [ -z "$1" ]; then
    echo "Usage: dconnect <container name> # to start a shell"
    return 1
  fi
  docker exec -it "$1" bash
}
function dsname() {
  if [ -z "$1" ]; then
    echo "Usage: dsname <container name>"
    return 1
  fi
  id=$(docker ps | grep "$1" | cut -d ' ' -f 1)
  if [ -z "$id" ]; then
    echo "Couldn't find container: '$1'"
    return 3
  fi
  echo "Stopping container '$1' ($id)"
  docker stop $id
}
alias dsall='docker kill $(docker ps -q)'
function dshell() {
  if [ -z "$1" ]; then
    echo "Usage: dshell <container name>"
    return 1
  fi
  id=$(docker ps | grep "$1" | cut -d ' ' -f 1)
  if [ -z "$id" ]; then
    echo "Couldn't find container: '$1'"
    return 3
  fi
  docker exec -it $id /bin/bash
}

alias homeassist="\
  docker run -d \
    --name homeassistant \
    --privileged \
    --restart=unless-stopped \
    -e TZ=America/New_York \
    -v '/home/dys/.config/Home Assistant/:/config' \
    --network=host \
    ghcr.io/home-assistant/home-assistant:stable"
alias neo4j="\
  docker run \
    --name argus \
    --publish 7474:7474 --publish 7687:7687 \
    --volume neo4j_data:/data \
    --env NEO4J_AUTH=neo4j/password \
    neo4j:latest"
    # -v $HOME/neo4j/logs:/logs \
    # -v $HOME/neo4j/import:/import \
    # -v $HOME/neo4j/plugins:/plugins \
    # --user="$(id -u):$(getent group users | awk -F: '{ print $3 }')" \

function spottoggle() {
  wid=$(xdotool search --name 'Spotify$' | tail -1)
  echo "Got Window ID: $wid"
  wstate=$(xwininfo -id $wid | grep "Map State:")
  echo "Window State: $wstate"

  if [[ "$wstate" == *IsUnMapped ]]; then
    echo "Mapping"
    xdotool windowmap $wid windowactivate $wid
  else
    xdotool windowunmap $wid
  fi
}

function spotmeta() {
  SP_DEST="org.mpris.MediaPlayer2.spotify"
  SP_PATH="/org/mpris/MediaPlayer2"
  SP_MEMB="org.mpris.MediaPlayer2.Player"
  dbus-send \
    --print-reply `# We need the reply.` \
    --dest=$SP_DEST \
    $SP_PATH \
    org.freedesktop.DBus.Properties.Get \
    string:"$SP_MEMB" string:'Metadata' |
    grep -Ev "^method" `# Ignore the first line.` |
    grep -Eo '("(.*)")|(\b[0-9][a-zA-Z0-9.]*\b)' `# Filter interesting fields.` |
    sed -E '2~2 a|' `# Mark odd fields.` |
    tr -d '\n' `# Remove all newlines.` |
    sed -E 's/\|/\n/g' `# Restore newlines.` |
    sed -E 's/(xesam:)|(mpris:)//' `# Remove ns prefixes.` |
    sed -E 's/^"//' `# Strip leading...` |
    sed -E 's/"$//' `# ...and trailing quotes.` |
    sed -E 's/"+/|/' `# Regard "" as seperator.` |
    sed -E 's/ +/ /g' `# Merge consecutive spaces.`
}
function spottrack() {
  OUT=$(
    spotmeta |
      grep --color=never -E "(title)|(album)|(artist)" |
      sed 's/^\(.\)/\U\1/' |
      column -t -s'|'
  )
  notify-send -t 1000 -i gtk-dialog-info Spotify "$OUT"
  echo "$OUT"
}

function trimtime() {
  if [[ -z "$1" || -z "$2" ]]; then
    cat <<HELP
Usage: trimtime <timestamp> <filename>
 Exe: trimtime 00:05:30 recording.mp4
   Produces a copy of the recording with
   the first 5 minutes and 30 seconds
   removed.
 Exe: trimtime -00:05:30 recording.mp4
   Produces a copy of the recording with
   the last 5 minutes and 30 seconds
   removed.
HELP
   return 2
  fi
  TIME="${1#-}"
  if [ "$TIME" != "$1" ]; then
    if [ "$LEN" == "N/A" ]; then
      echo "Couldn't find the length of '$2'" >&2
      return 3
    fi
    LEN=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$2" | sed 's/\..*//')
    IFS=':' read -r -a PART <<<$TIME
    readarray -td '' PART < <(printf '%s\0' "${PART[@]}" | tac -s '')
    [ -z "${PART[1]}" ] && PART[1]=0
    [ -z "${PART[2]}" ] && PART[2]=0
    REM=$(((((${PART[2]} * 60) + ${PART[1]}) * 60) + ${PART[0]}))
    NEWLEN=$(($LEN - $REM))
    SEXA=$(date -d@$NEWLEN -u +%H:%M:%S)
    OUT="${2%.*}.‒$SEXA.${2##*.}"

    echo "Writing To: $OUT"
    ffmpeg -t "$SEXA" -i "$2" -map 0 -c copy -- "file:$OUT"
  else
    OUT="${2%.*}.$1‒.${2##*.}"

    echo "Writing To: $OUT"
    ffmpeg -ss "$1" -i "$2" -map 0 -c copy -- "file:$OUT"
  fi
}
function joinvideos() {
  if [[ -z "$1" || -z "$2" ]]; then
    cat <<HELP
Usage: joinvideos <file #1> <file #2>
 Exe: joinvideos one.mp4 two.named.mp4
  Produces one.two.mp4 which contains
  the contents of two following those
  of one.
HELP
   return 2
  fi
  OUT=".${1##*.}"
  IN="$(tempfile)"
  for file in "$@"; do
    OUT="${file%%.*}$OUT"
    echo "file \"$PWD/$(echo $file | sed 's/"/\"/g')\"" >>"$IN"
  done

  echo "Writing To: $OUT"
  ffmpeg -f concat -safe 0 -i "$IN" -c copy "$OUT"
  rm "$IN"
}
function rotateVideo90() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: rotateMp490 <file #1>
 Exe: Usage: rotateMp490 stream.mp4
  Rotates a video 90
HELP
   return 2
  fi
  IN="$1"
  OUT="${1%.*}.rotated.${1##*.}"
  ffmpeg -i "$IN" -vf "transpose=1" "$OUT"
}

function timeToSeconds() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: timeToSeconds <timestamp>
 Exe: timeToSeconds 00:05:30
   Prints 330, the number of seconds
   in five minutes & 30 seconds.
HELP
   return 4
  fi
  IFS=':' read -r -a PART <<<$1
  readarray -td '' PART < <(printf '%s\0' "${PART[@]}" | tac -s '')
  [ -z "${PART[1]}" ] && PART[1]=0
  [ -z "${PART[2]}" ] && PART[2]=0
  SECS=$(((((${PART[2]} * 60) + ${PART[1]}) * 60) + ${PART[0]}))
  echo $SECS
}
function blur() {
  if [[ -z "$1" || -z "$2" || -z "$3" ]]; then
    cat <<HELP
Usage: blur <timestamp> <duration> <file>
 Exe: blur 00:05:30 20 recording.mp4
   Produces a copy of the recording with
   the entire frame blurred out for 20
   seconds stating at 5 minutes and 30
   seconds.
HELP
   return 4
  fi
  START=$(timeToSeconds "$1")
  DUR=$(timeToSeconds "$2")
  END=$(($START + $DUR))
  OUT="${3%.*}.blurred.${3##*.}"

  echo "Writing To: $OUT"
  ffmpeg -i "$3" -filter_complex "[0:v]boxblur=30:enable='between(t,$START,$END)'" -- "file:$OUT"
}

function mp42gif() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: vid2gif <file #1>
 Exe: vid2gif stream.mp4
  Produces stream.gif which contains
  the contents of the file an an animated GIF.
HELP
   return 2
  fi
  IN="$1"
  OUT="${1%.*}.gif"
  ffmpeg -i "$IN" -vf "fps=10,scale=320:-1:flags=lanczos" -c:v pam -f image2pipe - |
    convert -delay 10 - -loop 0 -layers optimize "$OUT"
}

function png2transparent() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: png2transparent <file #1>
 Exe: png2transparent 
  Produces stream.gif which contains
  the contents of the file an an animated GIF.
HELP
   return 2
  fi
  IN="$1"
  OUT="${1%.*}.transparent.png"
  color=$(convert "$IN" -format "%[pixel:p{0,0}]" info:-)
  convert "$IN" -alpha off -bordercolor $color -border 1 \
    \( \
    +clone -fuzz 30% -fill none -floodfill +0+0 $color \
    -alpha extract -geometry 200% -blur 0x0.5 \
    -morphology erode square:1 -geometry 50% \
    \) \
    -compose CopyOpacity -composite -shave 1 "$OUT"
}

function hevc2x264() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: hevc2x264 <file #1>
 Exe: hevc2x264 stream.mkv
  Produces stream.x264.mp4 which contains
  the contents of the file as x264.
HELP
   return 2
  fi
  IN="$1"
  OUT="${1%.*}.x264.mp4"
  ffmpeg -i "$IN" -map 0 -c:v libx264 -crf 18 -c:a copy "$OUT"
}

function vid2webm() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: vid2webm <file #1>
    Exe: vid2webm stream.mp4
    Produces libvpx encoded webm with Vorbis
    encoded audio.
HELP
   return 2
  fi
  IN="$1"
  OUT="${1%.*}.webm"
  ffmpeg -i "$IN" -c:v libvpx-vp9 -pass 1 \
          -qmin 7 -qmax 39 -crf 10 -an "$OUT"
  ffmpeg -i "$IN" -c:v libvpx-vp9 -pass 2 \
          -qmin 7 -qmax 39 -crf 10 -c:a libvorbis "$OUT"
}
function vid2VP8Webm() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: vid2VP8webm <file #1>
  Exe: vid2VP8Webm  stream.mp4
  Produces stream.webm encoded using VP8 which is conpatible
  with Safari on iOS. Audio is Vorbis encoded.
HELP
   return 2
  fi
  IN="$1"
  OUT="${1%.*}.webm"
  ffmpeg -i "$IN" -c:v libvpx -pass 1 \
          -qmin 7 -qmax 39 -crf 10 -an "$OUT"
  ffmpeg -i "$IN" -c:v libvpx -pass 2 \
          -qmin 7 -qmax 39 -crf 10 -c:a libvorbis "$OUT"
}

function vid2m4a() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: vid2m4a <file #1>
 Exe: vid2m4a stream.mp4
  Produces stream.m4a which contains
  the audio of the file.
HELP
   return 2
  fi
  IN="$1"
  OUT="${1%.*}.m4a"
  ffmpeg -i "$IN" -vn -c:a copy "$OUT"
}

function ghclearcache() {
  if [[ -z "$1" || -z "$2" ]]; then
    cat <<HELP
Usage: ghclearcache <repo> <pr number>
Exe: ghclearcache metafam/thegame 1542
HELP
   return 2
  fi
  gh extension list | grep -q "actions-cache" || \
    gh extension install actions/gh-actions-cache

  REPO=${1}
  BRANCH="refs/pull/${2}/merge"

  cacheKeys=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )

  set +e # Setting this to not fail the workflow while deleting
  for cacheKey in $cacheKeys; do
      gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
  done
}

# I've been thinking about the possibility that persistent patterns
# exist in electrical fields, but that they are too ephemeral to
# persist around the strengths that our reality functions at. I
# thought that perhaps the writings of Castaneda described
# interactions with these beings. That only when our biochemical
# processes aren't driven by our consciousness are they able to
# impenge.

# Make javascripts executable #ToDo: shorten
function reg_javascript() {
  sudo sh -c "echo ':javascript:M:://!::$(echo ~)/.../bin/js:' > /proc/sys/fs/binfmt_misc/register"
}
alias unreg_javascript="sudo sh -c \"echo -1 > /proc/sys/fs/binfmt_misc/javascript\""

alias nopasswd="( export d=~/.ssh; [ -e $d/id_rsa.pub ] || { mkdir -p $d; cd $d; ssh-keygen -t rsa; }; ssh-copy-id \$REMOTE )"

function randpass() {
  SIZE="${1:-32}"
  echo "Generating ${SIZE} character random password" 1>&2
  tr -cd '[:print:]' \
    </dev/urandom |
    tr -ds '[" =]' [:print:] |
    fold -w${SIZE} |
    head -n1
}

alias isotime='date +%Y-%m-%d@%H:%M:%S%:z'
function rlog() {
  log="log/$1.$(isotime).log"
  echo "Logging rake $1 | $log"
  rake $1 2>&1 >>"$log" &
  tail -f "$log"
}

# Setup remote login for GIT
function setupLogin {
  KEYDIR=~/"personal/keys/$REMOTE"
  [ -e "$KEYDIR" ] || mkdir --parents "$KEYDIR"
  for KEY in "$KEYDIR"/*; do
    if [ -e "$KEY" ]; then # Loops even with no matches
      echo "Testing: $KEY: "
      ssh -o PasswordAuthentication=no -i "$KEY" $REMOTE "exit 0" && break || echo "  Fail"
    fi
  done
  if [ ! -e "$KEY" ]; then
    echo "Generating ${KEYLENGTH:=3096}-bit key:"
    USER=$(whoami)
    echo "   User: ${user:=USER}"
    PASSWORD=
    echo "   Pass: ${PASSWORD:=00000}"
    unset PASSWORD
    HOST=$(hostname)
    echo "   Host: $host"
    timestamp=$(date +'%Y-%m-%d@%H:%m:%S')
    echo "   Time: $timestamp"
    Key="$KEYDIR/$timestamp.rsa key"
    echo "   Out: $KEY(.pub)?"

    if [ -e "$KEY" ]; then
      backup="$KEYDIR/"$(tempfile --prefix 'bak: ' --suffix " ${KEY##*/}")
      mv -v "$KEY" "$backup"
    fi
    if [ -e "$KEY.pub" ]; then
      backup="$KEYDIR/"$(tempfile --prefix 'bak: ' --suffix " ${KEY##*/}.pub")
      mv -v "$KEY.pub" "$backup"
    fi
    rm -fv "$KEY" "$KEY.pub"

    ssh-keygen -t rsa -b $KEYLENGTH -C "$USER@$HOST:$KEY" -f "$KEY" -P "$PASSWORD" |
      tee "$KEY.out.utf-8" $OUTPUT
    REMOTE_KEYS=.ssh/authorized_keys
    echo "Appending $KEY to $REMOTE:$REMOTE_KEYS" &&
      cat "$KEY.pub" | tee - | ssh $REMOTE "cat >> '$REMOTE_KEYS'"

    # Add tipspace make script to add git permissions and drop full access
    echo "   Bootstrap: ${BOOTSTRAP:=.../sys/lib/tip/drop/permission/ssh/bash}"
    [ -e "${BOOTSTRAP}" ] &&
      ssh -i "$KEY" $REMOTE "mkdir --parents ${BOOTSTRAP%/*}" &&
      scp -i "$KEY" -r "${BOOTSTRAP}" "$REMOTE:${BOOTSTRAP%/*}" &&
      ssh -i "$KEY" $REMOTE "${BOOTSTRAP##*/} '${BOOTSTRAP}'"
  fi
}

function git-fold() {
  [ $# != 2 ] && {
    cat <<HELP
Usage: git-fold <repo> <dir>
  Folds <repo> into the current repository at <dir>
HELP
    return -1
  }
  repo="$1"
  dir="$2"
  git remote rm git-fold-merge-project
  git remote add -f git-fold-merge-project "$repo"
  git merge -s ours --no-commit git-fold-merge-project/master
  git read-tree --prefix="$dir" -u git-fold-merge-project/master
  git commit -m "Folding in $repo @ $dir"
  git pull -s subtree git-fold-merge-project master
}

function ipfspubdir() {
  if [ -z "$1" ]; then
    echo <<HELP
Usage: ipfspubdir a/b/c/d/e.ext'

 Will add the file to ipfs in a nested directory tree
 matching the one used to execute the command. So, for
 example, the root of the usage command would contain
 a directory named "a". The normal $(ipfs add -w) command
 would have "e.ext" in the root.
HELP
    return 2
  fi
  DIR=$(dirname "$1")
  TMP=$(mktemp -d --suffix=.ipfspubdir)
  OUT="$TMP/$DIR"
  mkdir "$OUT"
  echo "Copying '$1' to '$OUT'"
  cp "$1" "$OUT" && ipfs add -r "$TMP"
  rm -rf "$TMP"
}

# From: http://www.cyberciti.biz/tips/spice-up-your-unix-linux-shell-scripts.html
function openports() {
  for port in {1..1023}; do
    (echo >/dev/tcp/localhost/$port) >/dev/null 2>&1 && echo "$port open"
  done
}

function sendhttpexample() {
  exec 3<>/dev/tcp/${1:-will.dhappy.org}/80

  printf "GET /~/config/bash HTTP/1.0\r\n" >&3
  printf "Accept: text/html, text/plain\r\n" >&3
  printf "Accept-Language: en\r\n" >&3
  printf "User-Agent: bash_script v.%s\r\n" "${BASH_VERSION}" >&3
  printf "\r\n" >&3

  while read LINE <&3; do
    echo $LINE
  done
}

# For invoking the correct handler for files from the command line
which xdg-open >/dev/null 2>/dev/null && \
  function start() {
    for file in "$@"; do
      xdg-open "$file"
    done
  }
alias r=start
which gio >/dev/null 2>/dev/null && alias open='gio open' && alias launch='gio launch'

alias duck-duck-go='ddg'

function startweb() {
  LOCALHOST=http://localhost:88
  if [[ -n "$1" && -d "$1" ]]; then
    pushd "$1" > /dev/null || return 10
    _lweb_descended=1
  fi
  DIR=$(pwd)
  SHORT=${DIR//*\/.../}
  [ "$DIR" == "$SHORT" ] && SHORT=${DIR//*\/tip\/}
  [ -n "$SHORT" ] && SHORT="$SHORT/"
  [[ -n "$1" && -f "$1" ]] && SHORT="$SHORT$1"
  start "$LOCALHOST/$SHORT"
  if [ -n "$_lweb_descended" ]; then
    popd > /dev/null
    unset _lweb_descended
  fi
}
function lweb() {
  if [ -z "$1" ]; then
    startweb
  else
    for file in "$@"; do
      startweb "$file"
    done
  fi
}

# In OSX, mplayer installs to the home directory
# That `which` doesn't return false in OSX when the program isn't present is dumb
function mplayer() {
  if [ -z "$MPLAYERCMD" ]; then
    if [ -e /usr/bin/mplayer ]; then
      MPLAYERCMD=/usr/bin/mplayer
    else
      MPLAYERCMD="$(find ~ -name mplayer | head -n1)"
    fi
  fi
  if [ "$0" == "-2ndaudio" ]; then
    shift
    MPLAYERARGS="-ao alsa:device=hw=1,0"
  fi
  "$MPLAYERCMD" $MPLAYERARGS "$@"
}

# Ubuntu maps these keys properly to the XFree86 commands
if [ ! -e /etc/debian_version ]; then
  USBDEVICES=/proc/bus/usb/devices
  [ -e $USBDEVICES ] && grep --silent "Ergonomic Keyboard 4000" $USBDEVICES && {
    xmodmap -e 'keycode 162=F22' 2>/dev/null # Play/Pause key on Microsoft's Natural Keyboard
    xmodmap -e 'keycode 234=F20' 2>/dev/null # Back key on Microsoft's Natural Keyboard
    xmodmap -e 'keycode 233=F21' 2>/dev/null # Forward key on Microsoft's Natural Keyboard
    xmodmap -e 'keycode 176=F19' 2>/dev/null # Volume increase key on Microsoft's Natural Keyboard
    xmodmap -e 'keycode 174=F18' 2>/dev/null # Volume decrease key on Microsoft's Natural Keyboard
    xmodmap -e 'keycode 160=F18' 2>/dev/null # Mute key on Microsoft's Natural Keyboard
  }
fi
function mp3reencode() {
  newfile="${1%mp3}new.mp3"
  lame --mp3input --preset standard "$1" "$newfile" && (
    du -h "$1" "$newfile"
    mv -i "$newfile" "$1"
  )
}

function mp3oggify() {
  artist=${1% - *}
  track=${1#* - }
  newfile="${1%mp3}ogg"
  lame --mp3input --decode --silent "$1" - | oggenc -o "$newfile" -a "$artist" -t "$track" - && (du -h "$1" "$newfile")
}

function wmaoggify() {
  track=${1#* - }
  newfile="${1%wma}ogg"
  mplayer -ao pcm -ao pcm:file="$newfile.temp" "$1"
  oggenc -o "$newfile" -a "$artist" -t "$track" "$newfile.temp" && (du -h "$1" "$newfile")
  rm -fv "$newfile.temp"
}

function reencode() {
  BASENAME="${1%%.*}"
  [ -e "$BASENAME.mkv" ] && {
    echo "$BASENAME.mkv already exists"
    return 1
  }

  # mencoder is missing the -x264encopts option so I'm dumping the
  # sources to files and reencoding, not ideal, but I'm clueless

  if [ ! -e "$BASENAME.h264.mkv" ]; then
    # the framerate has to be set on active streaming files

    mplayer -ao null -fps 25 -fixed-vo -noframedrop -vo yuv4mpeg -vo yuv4mpeg:file="$BASENAME.tmp.y4m" $*

    # from: http://odin.himinbi.org/Makefile.Coupling

    ENCOPTS="--progress --subme 7 --analyse all --me umh --8x8dct"
    ENCOPTS="$ENCOPTS --qp 23 --min-keyint 12 --keyint 125 --bime"
    ENCOPTS="$ENCOPTS --direct auto --filter 1:1 --ref 16 --mixed-refs"
    ENCOPTS="$ENCOPTS --bframes 5 --b-pyramid --weightb --b-rdo"
    ENCOPTS="$ENCOPTS --trellis 2 --cqm jvt"

    eval x264 -o "$BASENAME.h264.mkv" $ENCOPTS --fps 21.78927 --pass 1 --stats "$BASENAME.x264.stats" "$BASENAME.tmp.y4m"
    eval x264 -o "$BASENAME.h264.mkv" $ENCOPTS --fps 21.78927 --pass 2 --stats "$BASENAME.x264.stats" "$BASENAME.tmp.y4m"
  fi

  if [ ! -e "$BASENAME.tmp.ogg" ]; then
    COUNT=0
    for file in "$@"; do
      COUNT=$((COUNT + 1))
      mplayer -ao pcm -ao pcm:nowaveheader -ao pcm:file="$BASENAME.tmp.$COUNT.wav" -vo null "$file"
    done
    sox "$BASENAME".tmp.*.wav -t wav "$BASENAME.tmp.wav"
    oggenc -o "$BASENAME.tmp.ogg" "$BASENAME.tmp.wav"
    rm -f "$BASENAME".tmp*.wav
  fi

  mkvmerge -o "$BASENAME.mkv" "$BASENAME.h264.mkv" "$BASENAME.tmp.ogg"
}

function playmp3s() {
  file=$(date "+/tmp/%Y_%m_%d.m3u")
  if [ ! -e $file ]; then
    dirs=$(echo /mnt/media/ ~/.mldonkey/incoming/ /usr/share/music/)
    # [ -e "${dirs%* }" ] || dirs=$(echo ~/)
    echo "Finding media in $dirs"
    find $dirs \( -name \*.mp3 -or -name \*.ogg -or -name \*.wma -or -name \*.m4a \) \
      -size +1k -printf "%p\n" >$file
  fi
  settitle Music
  mplayer -shuffle -playlist $file
}

if [ "${BASH_VERSINFO[5]/apple/}" != "${BASH_VERSINFO[5]}" ]; then # in OSX
  alias dir="ls -G"
  alias flushdns="lookupd -flushcache"
  tset -i
elif [ "${BASH_VERSINFO[5]/solaris/}" != "${BASH_VERSINFO[5]}" ]; then # in solaris
  alias ls=dir
elif [ "${BASH_VERSINFO[5]/cygwin/}" != "${BASH_VERSINFO[5]}" ]; then # in windows
  KEY=CurrentInstallFolder
  WINDOWSSDK=$(reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows" /v $KEY 2>/dev/null | grep $KEY | sed -e 's/.*REG_SZ[[:space:]]*//')
  if [ ! -z "$WINDOWSSDK" ]; then
    WINDOWSSDK=$(cygpath -p "$WINDOWSSDK\bin")
    [ -e "$WINDOWSSDK" ] && PATH="$PATH:$WINDOWSSDK"
  fi

  # this fixes a problem with emacs not exiting properly
  # it will cause the terminal to break though if it is set here rather than in the global env
  [ -z "$CYGWIN" ] && export CYGWIN=tty
  export CYGWIN="$CYGWIN winsymlinks"

  # mingw's compiler needs to be used before cwywin's to compile QT stuff
  mingwdir="/cygdrive/c/Documents and Settings/$USERNAME/My Documents/Programs/mingw32/bin/"
  [ -d "$mingwdir" ] && export PATH="$mingwdir:$PATH"

  # to use the python image library, use the windows binary
  pythondir=$(echo "/cygdrive/c/Program Files/"[Pp]ython*)
  [ -d "$pythondir" ] && PATH="$pythondir:$PATH"

  # Include pathes for QT under Windows
  # QT's make system relies on make being called from QT rather than cygwin
  # export QTDIR=$(echo "/cygdrive/c/Documents and Settings/$USERNAME/My Documents/Programs/QT/"*)
  export QTDIR=$(echo "/cygdrive/c/Qt/"*)
  [ -d "$QTDIR" ] && export PATH="$QTDIR/bin/:$PATH"
  which make.bat >/dev/null 2>&1 && alias make="make.bat"

  PROGRAMS=${ProgramW6432}
  sevenzipdir="$(cygpath "$PROGRAMS")/7-Zip"
  [ -d "$sevenzipdir" ] && export PATH="$PATH:$sevenzipdir"

  alias dir="ls --color"
else
  # suse aliases dir to ls -l
  if which lsd >/dev/null; then
    alias dir >/dev/null 2>&1 || alias dir="lsd --color"
    alias ls="lsd --color always"
  fi
fi

# set a fancy prompt (non-color, unless we know we "want" color)
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
  color_prompt=yes
fi

## From gh copilot alias
ghcs() {
	TARGET="shell"
	local GH_DEBUG="$GH_DEBUG"
	local GH_HOST="$GH_HOST"

	read -r -d '' __USAGE <<-EOF
	Wrapper around \`gh copilot suggest\` to suggest a command based on a natural language description of the desired output effort.
	Supports executing suggested commands if applicable.

	USAGE
	  $FUNCNAME [flags] <prompt>

	FLAGS
	  -d, --debug              Enable debugging
	  -h, --help               Display help usage
	      --hostname           The GitHub host to use for authentication
	  -t, --target target      Target for suggestion; must be shell, gh, git
	                           default: "$TARGET"

	EXAMPLES

	- Guided experience
	  $ $FUNCNAME

	- Git use cases
	  $ $FUNCNAME -t git "Undo the most recent local commits"
	  $ $FUNCNAME -t git "Clean up local branches"
	  $ $FUNCNAME -t git "Setup LFS for images"

	- Working with the GitHub CLI in the terminal
	  $ $FUNCNAME -t gh "Create pull request"
	  $ $FUNCNAME -t gh "List pull requests waiting for my review"
	  $ $FUNCNAME -t gh "Summarize work I have done in issues and pull requests for promotion"

	- General use cases
	  $ $FUNCNAME "Kill processes holding onto deleted files"
	  $ $FUNCNAME "Test whether there are SSL/TLS issues with github.com"
	  $ $FUNCNAME "Convert SVG to PNG and resize"
	  $ $FUNCNAME "Convert MOV to animated PNG"
	EOF

	local OPT OPTARG OPTIND
	while getopts "dht:-:" OPT; do
		if [ "$OPT" = "-" ]; then     # long option: reformulate OPT and OPTARG
			OPT="${OPTARG%%=*}"       # extract long option name
			OPTARG="${OPTARG#"$OPT"}" # extract long option argument (may be empty)
			OPTARG="${OPTARG#=}"      # if long option argument, remove assigning `=`
		fi

		case "$OPT" in
			debug | d)
				GH_DEBUG=api
				;;

			help | h)
				echo "$__USAGE"
				return 0
				;;

			hostname)
				GH_HOST="$OPTARG"
				;;

			target | t)
				TARGET="$OPTARG"
				;;
		esac
	done

	# shift so that $@, $1, etc. refer to the non-option arguments
	shift "$((OPTIND-1))"

	TMPFILE="$(mktemp -t gh-copilotXXXXXX)"
	trap 'rm -f "$TMPFILE"' EXIT
	if GH_DEBUG="$GH_DEBUG" GH_HOST="$GH_HOST" gh copilot suggest -t "$TARGET" "$@" --shell-out "$TMPFILE"; then
		if [ -s "$TMPFILE" ]; then
			FIXED_CMD="$(cat $TMPFILE)"
			history -s $(history 1 | cut -d' ' -f4-); history -s "$FIXED_CMD"
			echo
			eval "$FIXED_CMD"
		fi
	else
		return 1
	fi
}

pe() {
	local GH_DEBUG="$GH_DEBUG"
	local GH_HOST="$GH_HOST"

	read -r -d '' __USAGE <<-EOF
	Wrapper around \`gh copilot explain\` to explain a given input command in natural language.

	USAGE
	  $FUNCNAME [flags] <command>

	FLAGS
	  -d, --debug      Enable debugging
	  -h, --help       Display help usage
	      --hostname   The GitHub host to use for authentication

	EXAMPLES

	# View disk usage, sorted by size
	$ $FUNCNAME 'du -sh | sort -h'

	# View git repository history as text graphical representation
	$ $FUNCNAME 'git log --oneline --graph --decorate --all'

	# Remove binary objects larger than 50 megabytes from git history
	$ $FUNCNAME 'bfg --strip-blobs-bigger-than 50M'
	EOF

	local OPT OPTARG OPTIND
	while getopts "dh-:" OPT; do
		if [ "$OPT" = "-" ]; then     # long option: reformulate OPT and OPTARG
			OPT="${OPTARG%%=*}"       # extract long option name
			OPTARG="${OPTARG#"$OPT"}" # extract long option argument (may be empty)
			OPTARG="${OPTARG#=}"      # if long option argument, remove assigning `=`
		fi

		case "$OPT" in
			debug | d)
				GH_DEBUG=api
				;;

			help | h)
				echo "$__USAGE"
				return 0
				;;

			hostname)
				GH_HOST="$OPTARG"
				;;
		esac
	done

	# shift so that $@, $1, etc. refer to the non-option arguments
	shift "$((OPTIND-1))"

	GH_DEBUG="$GH_DEBUG" GH_HOST="$GH_HOST" gh copilot explain "$@"
}


if [ ! "${BASH_VERSINFO[5]/solaris/}" != "${BASH_VERSINFO[5]}" ]; then # not in solaris
  alias emacs="emacs -nw"
fi

precmd_set_tip_dir() {
  TIPDIR="${PWD}/"
  if [[ "$TIPDIR" =~ .*/\.\.\./(.*) ]]; then
    TIPDIR="∅/${BASH_REMATCH[1]}"
  fi
  FROMGIT="$(git rev-parse --show-prefix 2>/dev/null)"
  if [[ $? -eq 0 ]]; then
    GITDIR="${TIPDIR%$FROMGIT}"
    GITDIR="${GITDIR%/}"
    TIPDIR="/${GITDIR##*/}/${FROMGIT}"
  fi
  FROMHOME="${TIPDIR#$HOME}"
  if [[ "$FROMHOME" != "$TIPDIR" ]]; then
    TIPDIR="~${FROMHOME}"
  fi
  export TIPDIR
}
# precmd_functions+=(precmd_set_tip_dir)

[[ "$(pwd)" == ~ && -d ... ]] && cd ...

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" 
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
source $HOME/.local/share/bash-completion/completions/deno.bash