浏览代码

Update scripts

Bryan Roessler 3 天之前
父节点
当前提交
0073cfdab5

+ 2 - 0
.gitignore

@@ -1,3 +1,5 @@
 .vscode/
 setup/
 hartmanlab/
+.env
+.old/

+ 1 - 0
dotfiles/.gitignore

@@ -0,0 +1 @@
+secrets/

+ 0 - 184
dotfiles/.zshrc

@@ -1,184 +0,0 @@
-### SHELL OPTIONS ###
-setopt autocd correct globdots extendedglob nomatch notify
-unsetopt beep
-bindkey -e
-
-### AUTOCOMPLETION ###
-zstyle ':completion::complete:*' gain-privileges 1
-zstyle ':completion:*' menu select
-zstyle ':completion:*:ssh:*' hosts
-autoload -Uz compinit
-compinit
-
-### HISTORY ###
-setopt share_history inc_append_history hist_expire_dups_first hist_reduce_blanks hist_find_no_dups
-HISTFILE=~/.histfile
-HISTSIZE=10000000
-SAVEHIST=100000
-HISTCONTROL=ignorespace
-
-# History search
-autoload -Uz up-line-or-beginning-search down-line-or-beginning-search
-zle -N up-line-or-beginning-search
-zle -N down-line-or-beginning-search
-[[ -n "${key[Up]}"   ]] && bindkey -- "${key[Up]}"   up-line-or-beginning-search
-[[ -n "${key[Down]}" ]] && bindkey -- "${key[Down]}" down-line-or-beginning-search
-
-### PROMPT ###
-autoload -Uz promptinit
-promptinit
-
-# Color codes
-# https://www.ditig.com/publications/256-colors-cheat-sheet
-
-# color root user red
-if [[ $USER == "root" ]]; then
-    user_color="red"
-else
-    user_color="white"
-fi
-
-# For OpenWRT
-[[ -z $HOSTNAME ]] && HOSTNAME=$(noglob uci get system.@system[0].hostname)
-
-# For toolbox
-if [[ -v TOOLBOX_PATH ]]; then
-  host_color=magenta
-else
-  case $HOSTNAME in;
-    laptop)
-      host_color=green
-      ;;
-    workstation)
-      host_color=red
-      ;;
-    bryan-pc)
-      host_color=cyan
-      ;;
-    time4vps)
-      host_color=blue
-      ;;
-    racknerd)
-      host_color=yellow
-      ;;
-    htpc)
-      host_color=214 # orange
-      ;;
-    hartmanlab)
-      host_color=magenta
-      ;;
-    router)
-      host_color=blue
-      ;;
-    ax6000)
-      host_color=87 # slate gray
-      ;;
-    home-router)
-      host_color=218 # pink
-      ;;
-    *)
-      echo "Hostname $HOSTNAME unknown, consider adding to .zshrc"
-      host_color=white
-      ;;
-  esac
-fi
-
-PS1="[%F{${user_color}}%n%F{white}@%{%F{${host_color}}%}%m%F{white}]%~$ "
-case $TERM in
-    xterm*)
-        precmd () {print -Pn "\e]0;${PWD/$HOME/\~}\a"}
-        ;;
-esac
-### PATH ###
-typeset -U PATH path
-BINPATH="$HOME/bin"
-GOPATH="$HOME/go"
-path+=("${GOPATH//://bin:}/bin" "$HOME/Documents/develop/scripts/shell" "$HOME/.local/bin" "$HOME/.local/bin/*")
-export PATH
-
-### ALIASES ###
-alias vmd='vmd -nt'
-alias -g dnf-list-files='dnf repoquery -l'
-alias -g gedit='gnome-text-editor'
-alias -g dnf='dnf5'
-alias xclip="xclip -selection c" # shouldn't need this on wayland, use wl-copy instead
-alias -g pdoman="podman"
-alias virtualenv-workon="workon"
-alias git-list="git ls-tree -r master --name-only"
-
-### KEYBINDINGS ###
-# create a zkbd compatible hash;
-# to add other keys to this hash, see: man 5 terminfo
-typeset -g -A key
-
-key[Home]="${terminfo[khome]}"
-key[End]="${terminfo[kend]}"
-key[Insert]="${terminfo[kich1]}"
-key[Backspace]="${terminfo[kbs]}"
-key[Delete]="${terminfo[kdch1]}"
-key[Up]="${terminfo[kcuu1]}"
-key[Down]="${terminfo[kcud1]}"
-key[Left]="${terminfo[kcub1]}"
-key[Right]="${terminfo[kcuf1]}"
-key[PageUp]="${terminfo[kpp]}"
-key[PageDown]="${terminfo[knp]}"
-key[ShiftTab]="${terminfo[kcbt]}"
-
-# setup key accordingly
-[[ -n "${key[Home]}"      ]] && bindkey -- "${key[Home]}"      beginning-of-line
-[[ -n "${key[End]}"       ]] && bindkey -- "${key[End]}"       end-of-line
-[[ -n "${key[Insert]}"    ]] && bindkey -- "${key[Insert]}"    overwrite-mode
-[[ -n "${key[Backspace]}" ]] && bindkey -- "${key[Backspace]}" backward-delete-char
-[[ -n "${key[Delete]}"    ]] && bindkey -- "${key[Delete]}"    delete-char
-[[ -n "${key[Up]}"        ]] && bindkey -- "${key[Up]}"        up-line-or-history
-[[ -n "${key[Down]}"      ]] && bindkey -- "${key[Down]}"      down-line-or-history
-[[ -n "${key[Left]}"      ]] && bindkey -- "${key[Left]}"      backward-char
-[[ -n "${key[Right]}"     ]] && bindkey -- "${key[Right]}"     forward-char
-[[ -n "${key[PageUp]}"    ]] && bindkey -- "${key[PageUp]}"    beginning-of-buffer-or-history
-[[ -n "${key[PageDown]}"  ]] && bindkey -- "${key[PageDown]}"  end-of-buffer-or-history
-[[ -n "${key[ShiftTab]}"  ]] && bindkey -- "${key[ShiftTab]}"  reverse-menu-complete
-
-# Finally, make sure the terminal is in application mode, when zle is
-# active. Only then are the values from $terminfo valid.
-if (( ${+terminfo[smkx]} && ${+terminfo[rmkx]} )); then
-	autoload -Uz add-zle-hook-widget
-	function zle_application_mode_start {
-		echoti smkx
-	}
-	function zle_application_mode_stop {
-		echoti rmkx
-	}
-	add-zle-hook-widget -Uz zle-line-init zle_application_mode_start
-	add-zle-hook-widget -Uz zle-line-finish zle_application_mode_stop
-fi
-
-# Functions
-function podman-update-images () {
-    podman images |grep -v REPOSITORY|awk '{print $1}'|xargs -L1 podman pull
-}
-
-function extract()
-{
-     if [ -f $1 ] ; then
-         case $1 in
-             *.tar.bz2)   tar xvjf $1     ;;
-             *.tar.gz)    tar xvzf $1     ;;
-             *.bz2)       bunzip2 $1      ;;
-             *.rar)       unrar x $1      ;;
-             *.gz)        gunzip $1       ;;
-             *.tar)       tar xvf $1      ;;
-             *.tbz2)      tar xvjf $1     ;;
-             *.tgz)       tar xvzf $1     ;;
-             *.zip)       unzip $1        ;;
-             *.Z)         uncompress $1   ;;
-             *.7z)        7z x $1         ;;
-             *)           echo "'$1' cannot be extracted via >extract<" ;;
-         esac
-     else
-         echo "'$1' is not a valid file"
-     fi
-}
-
-function buildah-prune() {
-    buildah containers | cut -d" " -f 1 | tail -n +2| xargs buildah rm
-}

+ 245 - 0
dotfiles/btrbk/.config/btrbk/btrbk.conf

@@ -0,0 +1,245 @@
+#
+# Example btrbk configuration file
+#
+#
+# Please refer to the btrbk.conf(5) man-page for a complete
+# description of all configuration options.
+# For more examples, see README.md included with this package.
+#
+#   btrbk.conf(5): <https://digint.ch/btrbk/doc/btrbk.conf.5.html>
+#   README.md:     <https://digint.ch/btrbk/doc/readme.html>
+#
+# Note that the options can be overridden per volume/subvolume/target
+# in the corresponding sections.
+#
+
+
+# Enable transaction log
+transaction_log            /var/log/btrbk.log
+
+# Specify SSH private key for remote connections
+ssh_identity               /home/bryan/.config/btrbk/id_ed25519
+ssh_user                   root
+
+# Use sudo if btrbk or lsbtr is run by regular user
+backend_local_user         btrfs-progs-sudo
+
+# Enable stream buffer. Adding a buffer between the sending and
+# receiving side is generally a good idea.
+# NOTE: If enabled, make sure to install the "mbuffer" package!
+stream_buffer              1g
+
+# Directory in which the btrfs snapshots are created. Relative to
+# <volume-directory> of the volume section.
+# If not set, the snapshots are created in <volume-directory>.
+#
+# If you want to set a custom name for the snapshot (and backups),
+# use the "snapshot_name" option within the subvolume section.
+#
+# NOTE: btrbk does not automatically create this directory, and the
+# snapshot creation will fail if it is not present.
+#
+snapshot_dir               .snapshots
+
+# Always create snapshots. Set this to "ondemand" to only create
+# snapshots if the target volume is reachable. Set this to "no" if
+# snapshot creation is done by another instance of btrbk.
+snapshot_create            onchange
+
+# Perform incremental backups (set to "strict" if you want to prevent
+# creation of non-incremental backups if no parent is found).
+#incremental                yes
+
+# Specify after what time (in full hours after midnight) backups/
+# snapshots are considered as a daily backup/snapshot
+#preserve_hour_of_day       0
+
+# Specify on which day of week weekly/monthly backups are to be
+# preserved.
+#preserve_day_of_week       sunday
+
+# Preserve all snapshots for a minimum period of time.
+#snapshot_preserve_min      1d
+
+# Retention policy for the source snapshots.
+#snapshot_preserve          <NN>h <NN>d <NN>w <NN>m <NN>y
+
+# Preserve all backup targets for a minimum period of time.
+#target_preserve_min        no
+
+# Retention policy for backup targets:
+#target_preserve            <NN>h <NN>d <NN>w <NN>m <NN>y
+
+# Retention policy for archives ("btrbk archive" command):
+#archive_preserve_min       no
+#archive_preserve           <NN>h <NN>d <NN>w <NN>m <NN>y
+
+# Enable compression for remote btrfs send/receive operations:
+#stream_compress            no
+#stream_compress_level      default
+#stream_compress_threads    default
+
+# Enable lock file support: Ensures that only one instance of btrbk
+# can be run at a time.
+lockfile                   /var/lock/btrbk.lock
+
+# Don't wait for transaction commit on deletion. Enable this to make
+# sure the deletion of subvolumes is committed to disk when btrbk
+# terminates.
+#btrfs_commit_delete no
+
+
+#
+# Volume section (optional): "volume <volume-directory>"
+#
+#   <volume-directory>  Base path within a btrfs filesystem
+#                       containing the subvolumes to be backuped
+#                       (usually the mount-point of a btrfs filesystem
+#                       mounted with subvolid=5 option).
+#
+# Subvolume section: "subvolume <subvolume-name>"
+#
+#   <subvolume-name>    Subvolume to be backuped, relative to
+#                       <volume-directory> in volume section.
+#
+# Target section: "target <type> <volume-directory>"
+#
+#   <type>              (optional) type, defaults to "send-receive".
+#   <volume-directory>  Directory within a btrfs filesystem
+#                       receiving the backups.
+#
+# NOTE: The parser does not care about indentation, this is only for
+# human readability. All options apply to the last section
+# encountered, overriding the corresponding option of the upper
+# section. This means that the global options must be set on top,
+# before any "volume", "subvolume" or "target section.
+#
+
+#
+# Example retention policy:
+#
+# snapshot_preserve_min   2d
+# snapshot_preserve       14d
+# target_preserve_min     no
+# target_preserve         20d 10w *m
+
+snapshot_preserve_min   2d
+snapshot_preserve       14d
+
+target_preserve_min     no
+target_preserve         14d 10w *m
+
+archive_preserve_min    latest
+archive_preserve        12m 10y
+
+# Global settings
+compat_remote busybox
+send_protocol 2
+
+# Root backup workaround, omit the volume section
+subvolume /
+  target_preserve 14d 10w 6m
+  snapshot_dir /.snapshots # Absolute path to snapshots dir
+  target /mnt/backup/workstation/root
+  # target ssh://router.lan/mnt/backup/workstation/root
+# target /run/media/bryan/backup/workstation/root
+# target ssh://home-router/mnt/backup/workstation/root
+
+volume /home
+  subvolume bryan
+    target /mnt/backup/workstation/home
+    # target ssh://router.lan/mnt/backup/workstation/home
+    target_preserve 14d 10w 6m
+    # target ssh://home-router/mnt/backup/workstation/home
+    # target /run/media/bryan/backup/workstation/home
+
+volume /mnt/downloads
+  subvolume downloads
+    target /mnt/backup/workstation/downloads
+    # target /run/media/bryan/backup/workstation/downloads
+
+#volume /mnt/array/media
+#  target /mnt/backup/media
+  # target ssh://router.lan/mnt/backup/media
+#  target ssh://home-router/mnt/backup/media
+#  subvolume music
+#    target_preserve_min all # for home-router to keep samba share (and safer overall)
+#  subvolume ebooks
+#  subvolume pictures
+
+# #
+# # Simple setup: Backup root and home to external disk
+# #
+# snapshot_dir /btrbk_snapshots
+# target       /mnt/btr_backup
+# subvolume    /
+# subvolume    /home
+
+
+# #
+# # Complex setup
+# #
+# # In order to keep things organized, it is recommended to use "volume"
+# # sections and mount the top-level subvolume (subvolid=5):
+# #
+# #  $ mount -o subvolid=5 /dev/sda1 /mnt/btr_pool
+# #
+# # Backup to external disk mounted on /mnt/btr_backup
+# volume /mnt/btr_pool
+#   # Create snapshots in /mnt/btr_pool/btrbk_snapshots
+#   snapshot_dir btrbk_snapshots
+
+#   # Target for all subvolume sections:
+#   target /mnt/btr_backup
+
+#   # Some default btrfs installations (e.g. Ubuntu) use "@" for rootfs
+#   # (mounted at "/") and "@home" (mounted at "/home"). Note that this
+#   # is only a naming convention.
+#   #subvolume @
+#   subvolume root
+#   subvolume home
+#   subvolume kvm
+#     # Use different retention policy for kvm backups:
+#     target_preserve 7d 4w
+
+
+# # Backup data to external disk as well as remote host
+# volume /mnt/btr_data
+#   subvolume  data
+#     # Always create snapshot, even if targets are unreachable
+#     snapshot_create always
+#     target /mnt/btr_backup
+#     target ssh://backup.my-remote-host.com/mnt/btr_backup
+
+
+# # Backup from remote host, with different naming
+# volume ssh://my-remote-host.com/mnt/btr_pool
+#   subvolume data_0
+#     snapshot_dir   snapshots/btrbk
+#     snapshot_name  data_main
+#     target /mnt/btr_backup/my-remote-host.com
+
+
+# # Backup on demand (noauto) to remote host running busybox, login as
+# # regular user using ssh-agent with current user name (ssh_user no)
+# # and default credentials (ssh_identity no).
+# volume /home
+#   noauto  yes
+#   compat  busybox
+#   backend_remote  btrfs-progs-sudo
+#   ssh_user      no
+#   ssh_identity  no
+
+#   target ssh://my-user-host.com/mnt/btr_backup/home
+#   subvolume  alice
+#   subvolume  bob
+
+
+# # Resume backups from remote host which runs its own btrbk instance
+# # creating snapshots for "home" in "/mnt/btr_pool/btrbk_snapshots".
+# volume ssh://my-remote-host.com/mnt/btr_pool
+#   snapshot_dir           btrbk_snapshots
+#   snapshot_create        no
+#   snapshot_preserve_min  all
+#   subvolume home
+#     target /mnt/btr_backup/my-remote-host.com

+ 24 - 0
dotfiles/deploy

@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+# Deploys the dotfiles in this directory using GNU stow
+set -euo pipefail
+
+# Get this script's directory
+SCRIPT_DIR=$(readlink -f "$(dirname "${BASH_SOURCE[0]}")")
+
+# Change to the dotfiles directory (push current dir on the stack)
+pushd "$SCRIPT_DIR" > /dev/null || exit 1
+
+# Loop through non-hidden top-level dirs and stow them
+for dir in */; do
+  [[ $dir == .* || $dir == secrets/ ]] && continue  # Skip dot-directories
+  echo "Stowing $dir"
+  if ! stow "$dir"; then
+    errorcode=$?
+    echo "Error stowing $dir"
+  fi
+done
+
+# Return to original directory
+popd > /dev/null || exit 1
+
+exit "${errorcode:-0}"

+ 8 - 0
dotfiles/git/.gitconfig

@@ -0,0 +1,8 @@
+# This is Git's per-user configuration file.
+[user]
+	email = bryanroessler@gmail.com
+	name = Bryan Roessler
+[color]
+	ui = auto
+[credential]
+	helper = cache

+ 31 - 0
dotfiles/tmux/.tmux.conf

@@ -0,0 +1,31 @@
+# Synchronize windows shortcut
+unbind a
+bind a set-window-option synchronize-panes
+
+# Use | and - to split a window vertically and horizontally instead of " and % respoectively
+unbind '"'
+unbind %
+bind | split-window -h -c "#{pane_current_path}"
+bind - split-window -v -c "#{pane_current_path}"
+
+# Automatically set window title
+set-window-option -g automatic-rename on
+set-option -g set-titles on
+
+# Use r to quickly reload tmux settings
+unbind r
+bind r \
+	source-file ~/.tmux.conf \;\
+	display 'Reloaded tmux config'
+
+# Set the history limit so we get lots of scrollback.
+setw -g history-limit 50000000
+
+# switch panes using Alt-arrow without prefix
+bind -n M-Left select-pane -L
+bind -n M-Right select-pane -R
+bind -n M-Up select-pane -U
+bind -n M-Down select-pane -D
+
+# Enable mouse mode
+set -g mouse on

+ 169 - 0
dotfiles/vim/.vimrc

@@ -0,0 +1,169 @@
+" File: .vimrc
+" Author: Jake Zimmerman <jake@zimmerman.io>
+"
+" How I configure Vim :P
+"
+
+" Gotta be first
+set nocompatible
+
+filetype off
+
+set rtp+=~/.vim/bundle/Vundle.vim
+call vundle#begin()
+
+Plugin 'VundleVim/Vundle.vim'
+
+" ----- Making Vim look good ------------------------------------------
+Plugin 'altercation/vim-colors-solarized'
+Plugin 'tomasr/molokai'
+Plugin 'vim-airline/vim-airline'
+Plugin 'vim-airline/vim-airline-themes'
+
+" ----- Vim as a programmer's text editor -----------------------------
+Plugin 'scrooloose/nerdtree'
+Plugin 'jistr/vim-nerdtree-tabs'
+Plugin 'vim-syntastic/syntastic'
+Plugin 'xolox/vim-misc'
+Plugin 'xolox/vim-easytags'
+Plugin 'majutsushi/tagbar'
+Plugin 'ctrlpvim/ctrlp.vim'
+Plugin 'vim-scripts/a.vim'
+
+" ----- Working with Git ----------------------------------------------
+Plugin 'airblade/vim-gitgutter'
+Plugin 'tpope/vim-fugitive'
+
+" ----- Other text editing features -----------------------------------
+Plugin 'Raimondi/delimitMate'
+
+" ----- man pages, tmux -----------------------------------------------
+Plugin 'jez/vim-superman'
+Plugin 'christoomey/vim-tmux-navigator'
+
+" ----- Syntax plugins ------------------------------------------------
+Plugin 'jez/vim-c0'
+Plugin 'jez/vim-ispc'
+Plugin 'kchmck/vim-coffee-script'
+
+" ---- Extras/Advanced plugins ----------------------------------------
+" Highlight and strip trailing whitespace
+"Plugin 'ntpeters/vim-better-whitespace'
+" Easily surround chunks of text
+"Plugin 'tpope/vim-surround'
+" Align CSV files at commas, align Markdown tables, and more
+"Plugin 'godlygeek/tabular'
+" Automaticall insert the closing HTML tag
+"Plugin 'HTML-AutoCloseTag'
+" Make tmux look like vim-airline (read README for extra instructions)
+"Plugin 'edkolev/tmuxline.vim'
+" All the other syntax plugins I use
+"Plugin 'ekalinin/Dockerfile.vim'
+"Plugin 'digitaltoad/vim-jade'
+"Plugin 'tpope/vim-liquid'
+"Plugin 'cakebaker/scss-syntax.vim'
+
+call vundle#end()
+
+filetype plugin indent on
+
+" --- General settings ---
+set backspace=indent,eol,start
+set ruler
+set number
+set showcmd
+set incsearch
+set hlsearch
+
+syntax on
+
+set mouse=a
+
+" We need this for plugins like Syntastic and vim-gitgutter which put symbols
+" in the sign column.
+hi clear SignColumn
+
+" ----- Plugin-Specific Settings --------------------------------------
+
+" ----- altercation/vim-colors-solarized settings -----
+" Toggle this to "light" for light colorscheme
+set background=dark
+
+" Uncomment the next line if your terminal is not configured for solarized
+let g:solarized_termcolors=256
+
+" Set the colorscheme
+colorscheme solarized
+
+
+" ----- bling/vim-airline settings -----
+" Always show statusbar
+set laststatus=2
+
+" Fancy arrow symbols, requires a patched font
+" To install a patched font, run over to
+"     https://github.com/abertsch/Menlo-for-Powerline
+" download all the .ttf files, double-click on them and click "Install"
+" Finally, uncomment the next line
+"let g:airline_powerline_fonts = 1
+
+" Show PASTE if in paste mode
+let g:airline_detect_paste=1
+
+" Show airline for tabs too
+let g:airline#extensions#tabline#enabled = 1
+
+" Use the solarized theme for the Airline status bar
+let g:airline_theme='solarized'
+
+" ----- jistr/vim-nerdtree-tabs -----
+" Open/close NERDTree Tabs with \t
+nmap <silent> <leader>t :NERDTreeTabsToggle<CR>
+" To have NERDTree always open on startup
+let g:nerdtree_tabs_open_on_console_startup = 1
+
+" ----- scrooloose/syntastic settings -----
+let g:syntastic_error_symbol = '✘'
+let g:syntastic_warning_symbol = "▲"
+augroup mySyntastic
+  au!
+  au FileType tex let b:syntastic_mode = "passive"
+augroup END
+
+
+" ----- xolox/vim-easytags settings -----
+" Where to look for tags files
+set tags=./tags;,~/.vimtags
+" Sensible defaults
+let g:easytags_events = ['BufReadPost', 'BufWritePost']
+let g:easytags_async = 1
+let g:easytags_dynamic_files = 2
+let g:easytags_resolve_links = 1
+let g:easytags_suppress_ctags_warning = 1
+
+" ----- majutsushi/tagbar settings -----
+" Open/close tagbar with \b
+nmap <silent> <leader>b :TagbarToggle<CR>
+" Uncomment to open tagbar automatically whenever possible
+"autocmd BufEnter * nested :call tagbar#autoopen(0)
+
+
+" ----- airblade/vim-gitgutter settings -----
+" In vim-airline, only display "hunks" if the diff is non-zero
+let g:airline#extensions#hunks#non_zero_only = 1
+
+
+" ----- Raimondi/delimitMate settings -----
+let delimitMate_expand_cr = 1
+augroup mydelimitMate
+  au!
+  au FileType markdown let b:delimitMate_nesting_quotes = ["`"]
+  au FileType tex let b:delimitMate_quotes = ""
+  au FileType tex let b:delimitMate_matchpairs = "(:),[:],{:},`:'"
+  au FileType python let b:delimitMate_nesting_quotes = ['"', "'"]
+augroup END
+
+" ----- jez/vim-superman settings -----
+" better man page support
+noremap K :SuperMan <cword><CR>
+

+ 152 - 0
dotfiles/zsh/.zshrc

@@ -0,0 +1,152 @@
+# SHELL OPTIONS
+setopt autocd correct globdots extendedglob nomatch notify \
+  share_history inc_append_history hist_expire_dups_first hist_reduce_blanks \
+  hist_find_no_dups hist_verify extended_history auto_pushd pushd_ignore_dups \
+  prompt_subst
+unsetopt beep
+bindkey -e
+
+# COMPLETION
+local compdump=${XDG_CACHE_HOME:-$HOME/.cache}/zsh/zcompdump-${HOST}-${ZSH_VERSION}
+[[ -d ${compdump:h} ]] || mkdir -p ${compdump:h}
+zstyle ':completion:*' menu select
+zstyle ':completion:*' gain-privileges 1
+zstyle ':completion:*:descriptions' format '%U%B%d%b%u'
+zmodload zsh/complist
+autoload -Uz compinit && compinit -d "$compdump"
+
+# HISTORY
+HISTFILE=${XDG_STATE_HOME:-$HOME/.local/state}/zsh/history
+[[ -d $HISTFILE:h ]] || mkdir -p $HISTFILE:h
+HISTSIZE=100000
+SAVEHIST=100000
+autoload -Uz up-line-or-beginning-search down-line-or-beginning-search
+zle -N up-line-or-beginning-search
+zle -N down-line-or-beginning-search
+
+# COLORS
+autoload -Uz colors && colors
+
+# PROMPT
+if [[ $EUID -eq 0 ]]; then
+  user_color=red
+else
+  user_color=white
+fi
+
+if [[ -v TOOLBOX_PATH ]]; then
+  host_color=magenta
+elif [[ -v DISTROBOX_ENTER_PATH ]]; then
+  host_color=15
+else
+  case $HOSTNAME in
+    laptop)       host_color=green ;;
+    workstation)  host_color=red ;;
+    bryan-pc)     host_color=cyan ;;
+    time4vps)     host_color=blue ;;
+    racknerd)     host_color=yellow ;;
+    htpc)         host_color=214 ;;
+    hartmanlab)   host_color=magenta ;;
+    router)       host_color=blue ;;
+    ax6000)       host_color=87 ;;
+    home-router)  host_color=218 ;;
+    vm-fedora*)   host_color=57 ;;
+    *)            host_color=white ;;
+  esac
+fi
+
+_git_prompt() {
+  local br
+  if br=$(git symbolic-ref --short HEAD 2>/dev/null); then
+    print -n " %F{242}($br)%f"
+  fi
+}
+
+PROMPT='[%F{'$user_color'}%n%f@%F{'$host_color'}%m%f]%~$(_git_prompt)%(!.#.$) '
+RPROMPT='%*'
+precmd() { print -Pn "\e]0;%n@%m: ${PWD/#$HOME/~}\a" }
+
+# HOSTNAME (OpenWRT)
+[[ -z $HOSTNAME ]] && HOSTNAME=$(noglob uci get system.@system[0].hostname 2>/dev/null)
+
+# PATHS
+typeset -U path PATH
+path=(
+  $HOME/bin
+  $HOME/.local/bin
+  $HOME/Documents/develop/scripts/shell
+  ${${GOPATH:-$HOME/go}//://bin:}/bin
+  $path
+)
+export PATH R_LIBS_USER="$HOME/R/qhtcp-workflow"
+
+# ALIASES
+alias ll='ls -lh'
+alias la='ls -A'
+alias vmd='vmd -nt'
+alias dnf-list-files='dnf repoquery -l'
+alias gedit='gnome-text-editor'
+alias xclip='xclip -selection c'
+alias pdoman='podman'
+alias workon='virtualenv-workon'
+alias git-list='git ls-tree -r HEAD --name-only'
+alias chatgpt='chatgpt --model gpt-4o'
+
+# KEYBINDINGS
+typeset -g -A key
+for k v in \
+  Home khome End kend Insert kich1 Backspace kbs Delete kdch1 \
+  Up kcuu1 Down kcud1 Left kcub1 Right kcuf1 PageUp kpp PageDown knp ShiftTab kcbt; do
+  [[ -n ${terminfo[$v]} ]] && key[$k]=${terminfo[$v]}
+ done
+bindkey -- ${key[Home]-}      beginning-of-line
+bindkey -- ${key[End]-}       end-of-line
+bindkey -- ${key[Insert]-}    overwrite-mode
+bindkey -- ${key[Backspace]-} backward-delete-char
+bindkey -- ${key[Delete]-}    delete-char
+bindkey -- ${key[Left]-}      backward-char
+bindkey -- ${key[Right]-}     forward-char
+bindkey -- ${key[PageUp]-}    beginning-of-buffer-or-history
+bindkey -- ${key[PageDown]-}  end-of-buffer-or-history
+bindkey -- ${key[ShiftTab]-}  reverse-menu-complete
+bindkey -- ${key[Up]-}        up-line-or-beginning-search
+bindkey -- ${key[Down]-}      down-line-or-beginning-search
+
+if (( ${+terminfo[smkx]} && ${+terminfo[rmkx]} )); then
+  autoload -Uz add-zle-hook-widget
+  zle_app_start()  { echoti smkx }
+  zle_app_finish() { echoti rmkx }
+  add-zle-hook-widget zle-line-init    zle_app_start
+  add-zle-hook-widget zle-line-finish  zle_app_finish
+fi
+
+# FUNCTIONS
+podman-update-images() {
+  podman images --format '{{.Repository}}' | grep -v '^<none>$' | xargs -r -L1 podman pull
+}
+extract() {
+  [[ $# -eq 0 ]] && { echo "usage: extract <archive...>" >&2; return 1; }
+  for a in "$@"; do
+    [[ ! -f $a ]] && { echo "$a: not a file" >&2; continue; }
+    case $a in
+      *.tar.bz2|*.tbz2) tar xvjf "$a" ;;
+      *.tar.gz|*.tgz)   tar xvzf "$a" ;;
+      *.tar.xz)         tar --xz -xvf "$a" ;;
+      *.tar.zst)        tar --use-compress-program=unzstd -xvf "$a" ;;
+      *.tar.lz)         tar --lzip -xvf "$a" ;;
+      *.tar)            tar xvf "$a" ;;
+      *.bz2)            bunzip2 "$a" ;;
+      *.gz)             gunzip "$a" ;;
+      *.xz)             unxz "$a" ;;
+      *.zst)            unzstd "$a" ;;
+      *.lz)             unlz "$a" ;;
+      *.zip)            unzip "$a" ;;
+      *.rar)            unrar x "$a" ;;
+      *.7z)             7z x "$a" ;;
+      *.Z)              uncompress "$a" ;;
+      *)                echo "$a: cannot extract" ;;
+    esac
+  done
+}
+buildah-prune() { buildah rm --all; }
+

+ 79 - 0
powershell/jriver-exclusions.ps1

@@ -0,0 +1,79 @@
+<#
+.SYNOPSIS
+  Adds JRiver Media Center folders, executables & processes to Windows Defender exclusions.
+
+.DESCRIPTION
+  powershell -ExecutionPolicy Bypass -File .\jriver-exclusions.ps1  
+#>
+
+# JRiver Media Center version to exclude
+$Version = 34
+
+function Add-ItemExclusion {
+    param(
+        [string]$Item,
+        [ValidateSet('Path','Process')]$Type
+    )
+    try {
+        if ($Type -eq 'Path') {
+            Add-MpPreference -ExclusionPath $Item -ErrorAction Stop
+        } else {
+            Add-MpPreference -ExclusionProcess $Item -ErrorAction Stop
+        }
+        Write-Host "Added ${Type}: ${Item}"
+    }
+    catch {
+        Write-Warning "Skipped/failed ${Type}: ${Item} - $_"
+    }
+}
+
+# Build base dir & lists
+$exeDir = "C:\Program Files\J River\Media Center $Version"
+Write-Host "Configuring JRiver Media Center version $Version"
+
+$folders = @(
+    'C:\Program Files\J River',
+    $exeDir,
+    "$Env:APPDATA\J River",
+    "$Env:APPDATA\J River\Media Center $Version"
+)
+
+$executables = @(
+    "$exeDir\Media Editor.exe",
+    "$exeDir\PackageInstaller.exe",
+    "$exeDir\JRCrashHandler.exe",
+    "$exeDir\JRMediaUninstall.exe",
+    "$exeDir\JRService.exe",
+    "$exeDir\JRWeb.exe",
+    "$exeDir\JRWorker.exe",
+    "$exeDir\MC$Version.exe",
+    "$exeDir\Media Center $Version.exe",
+    "C:\Windows\System32\MC$Version.exe",
+    "C:\Windows\SysWOW64\MC$Version.exe"
+)
+
+$processes = @(
+    "Media Center $Version.exe",
+    "MC$Version.exe",
+    'JRService.exe',
+    'JRWorker.exe'
+)
+
+# Add exclusions
+Write-Host "=== Adding folder exclusions ==="
+$folders | ForEach-Object { Add-ItemExclusion -Item $_ -Type Path }
+
+Write-Host "=== Adding file exclusions ==="
+$executables | ForEach-Object { Add-ItemExclusion -Item $_ -Type Path }
+
+Write-Host "=== Adding process exclusions ==="
+($processes + ($executables | Split-Path -Leaf) | Sort-Object -Unique) |
+    ForEach-Object { Add-ItemExclusion -Item $_ -Type Process }
+
+# Summary
+$pref = Get-MpPreference
+Write-Host ''
+Write-Host "=== Current Defender exclusion counts ==="
+Write-Host ("  Paths    : {0}" -f $pref.ExclusionPath.Count)
+Write-Host ("  Processes: {0}" -f $pref.ExclusionProcess.Count)
+Write-Host ''

+ 0 - 29
shell/random-word-pair

@@ -1,29 +0,0 @@
-#!/usr/bin/env bash
-# This script will create a random word pair with an underscore ex. turtle_ladder
-
-random_word_pair() {
-    # Constants 
-    local random_words num_random_words random_1 random_2 word_1 word_2
-    random_words=/usr/share/dict/words
-    # total number of non-random words available 
-    num_random_words=$(wc -l $random_words | cut -d" " -f 1)
-    # Get two random integers
-    random_1=$(shuf -i 1-"$num_random_words" -n 1)
-    random_2=$(shuf -i 1-"$num_random_words" -n 1)
-    # Get the nth word
-    word_1=$(sed "${random_1}q;d" "$random_words")
-    word_2=$(sed "${random_2}q;d" "$random_words")
-    # Sanitize words
-    word_1="${word_1,,}"
-    word_1="${word_1//-/}"
-    word_2="${word_2,,}"
-    word_2="${word_2//-/}"
-    echo "${word_1,,}_${word_2,,}"
-    return 0
-}
-
-# Allow this file to be executed directly if not being sourced
-if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
-    random_word_pair
-    exit $?
-fi

+ 38 - 0
shell/ssh-wrap

@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+# Usage: ./ssh-wrap user@host
+
+# Capture SSH output
+output=$(ssh "$@" 2>&1)
+
+# Print the SSH output so user sees what happened
+echo "$output"
+
+# Check if the known_hosts warning appears
+if echo "$output" | grep -q "REMOTE HOST IDENTIFICATION HAS CHANGED"; then
+    echo "It appears the host key has changed or a man-in-the-middle attack is possible."
+
+    # Extract the known_hosts file and line number from the "Offending RSA key in ..." line
+    # The line format typically is: "Offending RSA key in /path/to/known_hosts:line"
+    # We'll use awk to split by ':' and space to grab the file and line number
+    if offending_info=$(echo "$output" | grep "Offending RSA key in"); then
+        KNOWN_HOSTS_FILE=$(echo "$offending_info" | awk '{print $5}' | cut -d: -f1)
+        LINE_NUMBER=$(echo "$offending_info" | awk -F: '{print $NF}')
+
+        echo "Offending key detected in: $KNOWN_HOSTS_FILE on line: $LINE_NUMBER"
+        read -p "Would you like to remove this offending key line and re-attempt the SSH connection? [y/N]: " RESPONSE
+        if [[ "$RESPONSE" =~ ^[Yy]$ ]]; then
+            # Backup known_hosts
+            cp "$KNOWN_HOSTS_FILE" "$KNOWN_HOSTS_FILE.bak"
+            # Remove offending line
+            sed -i "${LINE_NUMBER}d" "$KNOWN_HOSTS_FILE"
+            echo "Offending key removed. Retrying SSH connection..."
+            ssh "$@"
+        else
+            echo "Key was not removed. Exiting."
+        fi
+    else
+        echo "Could not extract offending key information. Remove it manually if needed."
+    fi
+fi
+

+ 69 - 39
shell/tmux-management

@@ -1,49 +1,79 @@
 #!/usr/bin/env bash
-# This script launches a multi-pane tmux session for multiple remotes
-# TODO make remote sessions run in tmux too
-# Copyright 2024 Bryan C. Roessler
+# tmux‑management2 – open a tiled tmux window with one pane per host.
+# Each pane attaches to (or creates) a tmux session called $REMOTE_SESSION
+# on the target host.  The local host is always the *last* (active) pane.
 
-# Use DEBUG=1 ./tmux-management to enable debugging
+set -euo pipefail
+
+# Configuration (override with env vars if desired)
+HOSTS=(workstation laptop vm-fedora42) # hosts in pane order
+REMOTE_SESSION=${REMOTE_SESSION:-main} # tmux session on remotes
+SYNCHRONIZE=${SYNCHRONIZE:-1} # 1 = broadcast keystrokes
+INCLUDE_LOCAL=${INCLUDE_LOCAL:-1} # 0 = skip local host
+LOCAL_SHELL_ONLY=${LOCAL_SHELL_ONLY:-0} # 1 = plain shell locally
 DEBUG=${DEBUG:-0}
 
-debug() { (( DEBUG )) && echo "Debug: $*"; }
+debug() { if (( DEBUG )); then echo "Debug: $*"; fi; }
 
-HOSTS=(
-  workstation
-  laptop
-  #hartmanlab
-)
+# Returns 0 if $2 is found in nameref array $1
+array_contains() {
+  local -n arr=$1
+  local needle=$2
+  for element in "${arr[@]}"; do
+    [[ "$element" == "$needle" ]] && return 0
+  done
+  return 1
+}
 
-debug "Hosts list: ${HOSTS[*]}"
+LOCAL=$(hostname -s)
 
-# Remove localhost from HOSTS list
+# Build TARGETS list so that LOCAL is always last
 TARGETS=()
-for HOST in "${HOSTS[@]}"; do
-    if [[ "$HOST" != "$HOSTNAME" ]]; then
-        TARGETS+=("$HOST")
-    fi
+for h in "${HOSTS[@]}"; do
+  [[ $h != "$LOCAL" ]] && TARGETS+=("$h")
 done
-unset HOST
-
-# Create a unique session name from the remaining hosts
-SESSION=$(IFS=- ; echo "${TARGETS[*]}")
-
-debug "Targets: ${TARGETS[*]}"
-debug "Session: $SESSION"
-
-# Connect to existing session
-if tmux has-session -t "$SESSION" &> /dev/null; then
-  tmux attach -t "$SESSION";
-else # create new tmux session
-  tmux new-session -d -s "$SESSION" -n "$SESSION";
-  # Create a new pane for each TARGET
-  for TARGET in "${TARGETS[@]}"; do
-    tmux split-window -h;
-    tmux send "ssh $TARGET" enter;
-  done
-  tmux set-window-option synchronize-panes on;
-  tmux select-pane -t "$SESSION:0.0"
-  tmux send 'clear' enter;
-  tmux attach-session -t "$SESSION"
+if (( INCLUDE_LOCAL )); then
+  TARGETS+=("$LOCAL")
+fi
+
+(( ${#TARGETS[@]} )) || { echo "No hosts to connect to."; exit 1; }
+
+SESSION=$(IFS=-; echo "${TARGETS[*]}")
+debug "Session : $SESSION"
+debug "Targets : ${TARGETS[*]}"
+
+# Re‑attach if session already exists
+if tmux has-session -t "$SESSION" 2>/dev/null; then
+  exec tmux attach -t "$SESSION"
 fi
-unset TARGET
+
+# Builds the command that will run inside a pane
+open_cmd() {
+  local tgt=$1
+  if [[ $tgt == "$LOCAL" ]]; then
+    if (( LOCAL_SHELL_ONLY )); then
+      printf '%q -l' "${SHELL:-bash}"
+    else
+      printf 'tmux -L %q new -A -s %q' "${SESSION}_local" "$REMOTE_SESSION"
+    fi
+  else
+    printf 'ssh -t %q tmux new -A -s %q' "$tgt" "$REMOTE_SESSION"
+  fi
+}
+
+# Create the first pane
+tmux new-session -d -s "$SESSION" -n "$SESSION" "$(open_cmd "${TARGETS[0]}")"
+
+# Create remaining panes
+for tgt in "${TARGETS[@]:1}"; do
+  tmux split-window -t "$SESSION:0" -h "$(open_cmd "$tgt")"
+done
+
+tmux select-layout -t "$SESSION:0" tiled
+((SYNCHRONIZE)) && tmux setw -t "$SESSION:0" synchronize-panes on
+
+# Activate the last pane (local host)
+local_index=$(( ${#TARGETS[@]} - 1 ))
+tmux select-pane -t "$SESSION:0.$local_index"
+
+exec tmux attach -t "$SESSION"

+ 47 - 0
systemd/autologin@.service

@@ -0,0 +1,47 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=Getty on %I
+Documentation=man:agetty(8) man:systemd-getty-generator(8)
+Documentation=http://0pointer.de/blog/projects/serial-console.html
+After=systemd-user-sessions.service plymouth-quit-wait.service
+After=rc-local.service
+
+# If additional gettys are spawned during boot then we should make
+# sure that this is synchronized before getty.target, even though
+# getty.target didn't actually pull it in.
+Before=getty.target
+IgnoreOnIsolate=yes
+
+# On systems without virtual consoles, don't start any getty. Note
+# that serial gettys are covered by serial-getty@.service, not this
+# unit.
+ConditionPathExists=/dev/tty0
+
+[Service]
+# the VT is cleared by TTYVTDisallocate
+ExecStart=-/sbin/agetty --noclear -a %I $TERM
+Type=idle
+Restart=always
+RestartSec=0
+UtmpIdentifier=%I
+TTYPath=/dev/%I
+TTYReset=yes
+TTYVHangup=yes
+TTYVTDisallocate=yes
+KillMode=process
+IgnoreSIGPIPE=no
+SendSIGHUP=yes
+
+# Unset locale for the console getty since the console has problems
+# displaying some internationalized messages.
+Environment=LANG= LANGUAGE= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION=
+
+[Install]
+WantedBy=getty.target
+DefaultInstance=tty1