5deecedda0bb

Merge.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Tue, 04 Feb 2020 09:24:12 -0500
parents 71b4b4adee33 (current diff) 8d1c68b94471 (diff)
children dccf3005b8fe
branches/tags (none)
files fish/functions/pbc.fish fish/functions/pbp.fish fish/functions/pbpb.fish servers/bash_profile servers/bin/collapse servers/bin/cuts servers/bin/f

Changes

--- a/bash_profile	Tue Feb 04 09:23:46 2020 -0500
+++ b/bash_profile	Tue Feb 04 09:24:12 2020 -0500
@@ -23,7 +23,7 @@
 ORANGE=$'\e[33m'
 BLUE=$'\e[34m'
 PINK=$'\e[35m'
-CYAN=$'\e[36m'
+# CYAN=$'\e[36m'
 
 function last_return_value() {
     x="$?"
@@ -67,8 +67,37 @@
     }
 fi
 
-export PATH=~/bin:~/src/dotfiles/bin:~/src/dotfiles/lisp/bin:/usr/local/bin/:$PATH
-export PAGER=less
+function prepend_to_path {
+    if test -d "$1"; then
+        PATH="$1":"$PATH"
+    fi
+}
+
+PATH="/sbin"
+prepend_to_path "/bin"
+prepend_to_path "/usr/bin"
+prepend_to_path "/usr/sbin"
+prepend_to_path "/usr/local/bin"
+prepend_to_path "/usr/local/sbin"
+prepend_to_path "/usr/local/go/bin"
+prepend_to_path "/usr/games"
+prepend_to_path "/snap/bin"
+prepend_to_path "$HOME/.local/bin"
+prepend_to_path "$HOME/.go/bin"
+prepend_to_path "$HOME/src/dotfiles/lisp/bin"
+prepend_to_path "$HOME/src/dotfiles/bin"
+prepend_to_path "$HOME/src/hg"
+prepend_to_path "$HOME/bin"
+export PATH
+
+export LESS_TERMCAP_mb=$(printf '\e[01;31m')       # begin blinking
+export LESS_TERMCAP_md=$(printf '\e[01;38;5;74m')  # begin bold
+export LESS_TERMCAP_me=$(printf '\e[0m')           # end mode
+export LESS_TERMCAP_se=$(printf '\e[0m')           # end standout-mode
+export LESS_TERMCAP_so=$(printf '\e[38;5;246m')    # begin standout-mode - info box
+export LESS_TERMCAP_ue=$(printf '\e[0m')           # end underline
+export LESS_TERMCAP_us=$(printf '\e[04;38;5;146m') # begin underline
+export PAGER='less -iX'
 
 function psg() {
     ps auxww | grep --color=always "$@" | grep -v grep | collapse | cuts -f 2,11-
--- a/bin/backup-backblaze	Tue Feb 04 09:23:46 2020 -0500
+++ b/bin/backup-backblaze	Tue Feb 04 09:24:12 2020 -0500
@@ -2,6 +2,9 @@
 
 set -euo pipefail
 
+
+ban "Backblaze"
+
 source /home/sjl/.restic-backblaze-creds
 
 restic --repo b2:backups-ouroboros:restic-repo \
--- a/bin/backup-local	Tue Feb 04 09:23:46 2020 -0500
+++ b/bin/backup-local	Tue Feb 04 09:24:12 2020 -0500
@@ -2,6 +2,8 @@
 
 set -euo pipefail
 
+ban -F metal "NAS"
+
 restic --repo /mnt/cryo/restic-ouroboros/repo \
        --exclude-file=/home/sjl/src/dotfiles/restic/excludes.txt \
        --password-file /home/sjl/.restic-password-local \
--- a/bin/bootstrap.sh	Tue Feb 04 09:23:46 2020 -0500
+++ b/bin/bootstrap.sh	Tue Feb 04 09:24:12 2020 -0500
@@ -39,6 +39,7 @@
 ensure_link "src/dotfiles/fish/functions"         ".config/fish/functions"
 ensure_link "src/dotfiles/gitconfig"              ".gitconfig"
 ensure_link "src/dotfiles/gitignore"              ".gitignore"
+ensure_link "src/dotfiles/gnuplot"                ".gnuplot"
 ensure_link "src/dotfiles/hgignore"               ".hgignore"
 ensure_link "src/dotfiles/lisprc"                 ".lisprc"
 ensure_link "src/dotfiles/lispwords"              ".lispwords"
--- a/bin/disks	Tue Feb 04 09:23:46 2020 -0500
+++ b/bin/disks	Tue Feb 04 09:24:12 2020 -0500
@@ -2,7 +2,15 @@
 
 set -euo pipefail
 
-lsblk -o name,mountpoint,model,label,size,fstype | egrep -v "^loop" 
+lsblk -o name,mountpoint,model,label,size,fstype | grep -Pv "^loop" | awk '
+NR>1 && /^[a-zA-Z]/ { print "-----------------------------------------------------------------------------------------------------------------------" }
+                    { print $0 }
+'
 echo
 echo
-df -h | egrep -v '^/dev/loop' | egrep -v tmpfs
+echo
+
+OUT=$(df -h)
+echo "$OUT" | head -1
+echo "$OUT" | head -1 | sed 's/./-/g'
+echo "$OUT" | tail +2 | grep -Pv '^/dev/loop' | grep -Pv tmpfs | sort -k6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/e	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+"$EDITOR" "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/external-ip	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+dig @resolver1.opendns.com ANY myip.opendns.com +short
+
--- a/bin/mangle-signature	Tue Feb 04 09:23:46 2020 -0500
+++ b/bin/mangle-signature	Tue Feb 04 09:24:12 2020 -0500
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
 
-cat
+sed -Ee 's/^-- $/--  /'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/nnl	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+tr -d '\n'
--- a/bin/pastebin	Tue Feb 04 09:23:46 2020 -0500
+++ b/bin/pastebin	Tue Feb 04 09:24:12 2020 -0500
@@ -2,11 +2,8 @@
 
 set -euo pipefail
 
-PASTE_SHA=$(ssh paste.stevelosh.com 'cat > tmppaste && sha1sum tmppaste | cut -d" " -f1 && mv tmppaste /var/www/paste/`sha1sum tmppaste | cut -d" " -f1`')
+PASTE_SHA=$(ssh paste.stevelosh.com -- 'cat > tmppaste && sha1sum tmppaste | cut -d" " -f1 && mv tmppaste /var/www/paste/`sha1sum tmppaste | cut -d" " -f1`')
+URL="https://paste.stevelosh.com/$PASTE_SHA"
 
-echo -n "https://paste.stevelosh.com/$PASTE_SHA" | pbcopy
-echo -n 'Copied '
-tput bold
-pbpaste
-tput sgr0
-echo ' to the clipboard.'
+echo -n "$URL" | pbcopy
+echo "Copied $URL to the clipboard."
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/pbc	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,1 @@
+pbcopy
\ No newline at end of file
--- a/bin/pbcopy	Tue Feb 04 09:23:46 2020 -0500
+++ b/bin/pbcopy	Tue Feb 04 09:24:12 2020 -0500
@@ -1,3 +1,5 @@
 #!/usr/bin/env bash
 
-xclip -selection clipboard -i
+set -euo pipefail
+
+xsel --clipboard --input
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/pbp	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,1 @@
+pbpaste
\ No newline at end of file
--- a/bin/pbpaste	Tue Feb 04 09:23:46 2020 -0500
+++ b/bin/pbpaste	Tue Feb 04 09:24:12 2020 -0500
@@ -1,3 +1,5 @@
 #!/usr/bin/env bash
 
-xclip -selection clipboard -o
+set -euo pipefail
+
+xsel --clipboard --output
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/u	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+du -hd1 "$@"
--- a/fish/config.fish	Tue Feb 04 09:23:46 2020 -0500
+++ b/fish/config.fish	Tue Feb 04 09:24:12 2020 -0500
@@ -13,6 +13,7 @@
 function essh; nvim ~/.ssh/config; end
 
 function js; cd ~/scratch; end
+function jd; cd /dump; end
 
 function histgrep; history | grep "$argv" | tac; end
 
@@ -85,6 +86,7 @@
         end
     end
 end
+
 set -gx PATH "/sbin"
 prepend_to_path "/snap/bin"
 prepend_to_path "/usr/sbin"
@@ -107,7 +109,7 @@
 set -g -x EDITOR nvim
 set -g -x COMMAND_MODE unix2003
 set -g -x RUBYOPT rubygems
-set -g -x PAGER 'less -X'
+set -g -x PAGER 'less -iX'
 # set -g -x _JAVA_OPTIONS "-Djava.awt.headless=true"
 
 set -g -x GPG_TTY (tty)
@@ -143,32 +145,47 @@
 # }}}
 # Prompt {{{
 
-set normal (set_color normal)
-set magenta (set_color magenta)
-set yellow (set_color yellow)
-set green (set_color green)
-set cyan (set_color cyan)
-set gray (set_color -o black)
+if status --is-interactive
+    set normal (set_color normal)
+    set magenta (set_color magenta)
+    set yellow (set_color yellow)
+    set green (set_color green)
+    set cyan (set_color cyan)
+    set gray (set_color -o black)
 
-set hg_promptstring "\
+    set hg_promptstring "\
 < on $magenta<branch>$normal>\
 < at $cyan<bookmark>$normal>\
 $green<status|modified|unknown><update>$normal\
 " 2>/dev/null
 
+    if test -n "$SSH_CLIENT"
+        or test -n "$SSH_TTY"
+        set host_color (set_color cyan)
+        set want_vcs_prompts 0
+    else
+        set host_color (set_color yellow)
+        set want_vcs_prompts 1
+    end
+end
+
 function hg_prompt
-    hg prompt --angle-brackets $hg_promptstring 2>/dev/null
+    if test -z "$NOVCSPROMPT"
+        hg prompt --angle-brackets $hg_promptstring 2>/dev/null
+    end
 end
 
 function git_prompt
-    if git root >/dev/null 2>&1
-        set_color normal
-        printf ' on '
-        set_color magenta
-        printf '%s' (git current-branch ^/dev/null)
-        set_color green
-        git_prompt_status
-        set_color normal
+    if test -z "$NOVCSPROMPT"
+        if git root >/dev/null 2>&1
+            set_color normal
+            printf ' on '
+            set_color magenta
+            printf '%s' (git current-branch ^/dev/null)
+            set_color green
+            git_prompt_status
+            set_color normal
+        end
     end
 end
 
@@ -176,14 +193,6 @@
     echo $PWD | sed -e "s|^$HOME|~|"
 end
 
-if test -n "$SSH_CLIENT"
-    or test -n "$SSH_TTY"
-    set host_color (set_color cyan)
-    set want_vcs_prompts 0
-else
-    set host_color (set_color yellow)
-    set want_vcs_prompts 1
-end
 
 function fish_prompt
     set last_status $status
--- a/fish/functions/pbc.fish	Tue Feb 04 09:23:46 2020 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-function pbc -d "pbcopy"
-    xsel --clipboard --input
-end
--- a/fish/functions/pbp.fish	Tue Feb 04 09:23:46 2020 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-function pbp -d "pbpaste"
-    xsel --clipboard
-end
--- a/fish/functions/pbpb.fish	Tue Feb 04 09:23:46 2020 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-function pbpb -d "pbpaste to pastebin site"
-    pbp | pb
-end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gnuplot	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,51 @@
+# Basic Settings ---------------------------------------------------------- {{{
+
+set encoding utf8
+set terminal qt noraise
+set samples 1000
+
+# }}}
+# Constants --------------------------------------------------------------- {{{
+
+tau = 2 * pi
+e = 2.71828182845905
+r2 = sqrt(2.0)
+
+# }}}
+# Utility Functions ------------------------------------------------------- {{{
+
+min(a, b) = (a<b) ? a : b
+max(a, b) = (a>b) ? a : b
+
+# }}}
+# Exporting --------------------------------------------------------------- {{{
+
+export(file, terminal) = sprintf( \
+        "set terminal push;" . \
+        "set terminal %s;" . \
+        "set output '%s';" . \
+        "replot;" . \
+        "set output;" . \
+        "set terminal pop;" . \
+        "print system('realpath %s | nnl | pbcopy');" \
+    , terminal, file, file)
+
+export_pdf(file) = export(file . '.pdf', "pdfcairo")
+export_png(file) = export(file . '.png', "pngcairo")
+
+pdf = "eval export_pdf('graph')"
+png = "eval export_png('graph')"
+
+# }}}
+# Other ------------------------------------------------------------------- {{{
+
+kdens(file, column, bandwidth) = sprintf( \
+        "stats '%s' using %d;" . \
+        "plot '%s' using %d:(1.0/STATS_records) smooth kdensity bandwidth %f;" \
+    , file, column, file, column, bandwidth)
+
+cdf(file, column) = sprintf( \
+        "plot '%s' using %d:(1.0) smooth cnormal;" \
+    , file, column)
+
+# }}}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/lines.lisp	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,477 @@
+(eval-when (:compile-toplevel :load-toplevel :execute)
+  (ql:quickload '(:adopt :cl-ppcre :with-user-abort) :silent t))
+
+(defpackage :lines
+  (:use :cl)
+  (:export :toplevel :*ui*))
+
+(in-package :lines)
+
+;; TODO: Optimize by eliminating collection when all matchers are in order.
+
+;;;; Configuration ------------------------------------------------------------
+(defparameter *version* "1.0.0")
+(defparameter *index-base* 0)
+(defparameter *include-numbers* nil)
+(defparameter *limit* nil)
+
+
+;;;; Functionality ------------------------------------------------------------
+(defclass matcher ()
+  ((designator :type string :initarg :designator :accessor designator)))
+
+(defmethod print-object ((o matcher) stream)
+  (print-unreadable-object (o stream :type t)
+    (format stream "~S" (designator o))))
+
+(defgeneric matches-line-p (matcher line-number))
+(defgeneric map-matching-lines (matcher function min max))
+(defgeneric maximum (matcher))
+
+
+(defclass single-line-matcher (matcher)
+  ((n :type (integer 0) :initarg :n :accessor n)))
+
+(defmethod matches-line-p ((matcher single-line-matcher) i)
+  (= (n matcher) i))
+
+(defmethod map-matching-lines ((matcher single-line-matcher) function min max)
+  (when (<= min (n matcher) max)
+    (funcall function (n matcher))))
+
+(defmethod maximum ((matcher single-line-matcher))
+  (n matcher))
+
+
+(defclass range-matcher (matcher)
+  ((m :type (or null (integer 0)) :initarg :m :accessor m)
+   (n :type (or null (integer 0)) :initarg :n :accessor n)))
+
+(defmethod matches-line-p ((matcher range-matcher) i)
+  (let ((m (m matcher))
+        (n (n matcher)))
+    (cond ((null m) (if (null n)
+                      t
+                      (<= i n)))
+          ((null n) (<= m i))
+          (t (<= m i n)))))
+
+(defmethod map-matching-lines ((matcher range-matcher) function min max)
+  (loop :with m = (or (m matcher) min)
+        :with n = (or (n matcher) max)
+        :for i :from (max m min) :to (min n max)
+        :do (funcall function i)))
+
+(defmethod maximum ((matcher range-matcher))
+  (n matcher))
+
+
+(defclass modulo-matcher (matcher)
+  ((n :type (integer 0) :initarg :n :accessor n)
+   (modulus :type (integer 1) :initarg :modulus :accessor modulus)))
+
+(defmethod matches-line-p ((matcher modulo-matcher) i)
+  (= (mod i (modulus matcher))
+     (n matcher)))
+
+(defmethod map-matching-lines ((matcher modulo-matcher) function min max)
+  (loop
+    :with n = (n matcher)
+    :with modulus = (modulus matcher)
+    :with start = (if (< n min)
+                    (+ n modulus)
+                    n)
+    :for i :from start :to max :by modulus
+    :do (funcall function i)))
+
+(defmethod maximum ((matcher modulo-matcher))
+  nil)
+
+
+(defun parse-single-line-designator (designator)
+  (ppcre:register-groups-bind
+      ((#'parse-integer n))
+      ("^(\\d+)$" designator)
+    (make-instance 'single-line-matcher :designator designator :n n)))
+
+(defun parse-range-designator (designator)
+  (ppcre:register-groups-bind
+      ((#'parse-integer m n))
+      ("^(\\d+)?-(\\d+)?$" designator)
+    (when (and m n)
+      (assert (<= m n) ()
+        "Bad line range designator ~S: start (~D) must not be greater than end (~D)."
+        designator m n))
+    (make-instance 'range-matcher :designator designator :m m :n n)))
+
+(defun parse-modulo-designator (designator)
+  (ppcre:register-groups-bind
+      ((#'parse-integer n modulus))
+      ("^(\\d+)?m(\\d+)$" designator)
+    (when (null n)
+      (setf n 0))
+    (assert (< n modulus) ()
+      "Bad modulo designator ~S: offset (~D) must be less than modulus (~D)."
+      designator n modulus)
+    (make-instance 'modulo-matcher :designator designator :n n :modulus modulus)))
+
+(defun parse-line-designator (designator)
+  (or (parse-single-line-designator designator)
+      (parse-range-designator designator)
+      (parse-modulo-designator designator)
+      (error "Could not parse line designator ~S" designator)))
+
+(defun parse-line-designators (designators)
+  (mapcar #'parse-line-designator (ppcre:split "," designators)))
+
+
+(defun dbg (&rest args)
+  (apply #'format *error-output* args)
+  (finish-output *error-output*))
+
+(defun compute-limit (matchers)
+  (let ((maxes (mapcar #'maximum matchers)))
+    (unless (some #'null maxes)
+      (reduce #'max maxes))))
+
+(defun collect-lines (matchers)
+  (loop
+    :with limit = (compute-limit matchers)
+    :with min = *index-base*
+    :with max = nil
+    :with lines = (make-hash-table)
+    :for i :from min
+    :for line = (read-line *standard-input* nil)
+    :while line
+    :while (or (null limit) (<= i limit))
+    :do (progn (setf max i)
+               (dolist (matcher matchers)
+                 (when (matches-line-p matcher i)
+                   (setf (gethash i lines) line))))
+    :finally (return (values lines min max))))
+
+
+(defun output-line (line i)
+  (when i
+    (format *standard-output* "~D " i))
+  (write-line line))
+
+(defun run-slow (matchers)
+  (let ((include-numbers *include-numbers*))
+    (multiple-value-bind (lines min max) (collect-lines matchers)
+      (dolist (matcher matchers)
+        (map-matching-lines
+          matcher
+          (lambda (i)
+            (output-line (gethash i lines)
+                         (when include-numbers i)))
+          min max)))))
+
+(defun run-fast (matcher)
+  (loop
+    :with limit = (when *limit* (+ *index-base* *limit*))
+    :with include-numbers = *include-numbers*
+    :for i :from *index-base*
+    :for line = (read-line *standard-input* nil)
+    :while (or (null limit) (< i limit))
+    :while line
+    :when (zerop (mod i 100000))
+    :do (progn #+sbcl (sb-ext:gc))
+    :when (matches-line-p matcher i)
+    :do (output-line line (when include-numbers i))))
+
+(defun run (line-designators)
+  (let ((matchers (parse-line-designators line-designators)))
+    (if (= 1 (length matchers))
+      (run-fast (first matchers))
+      (run-slow matchers)))
+  (values))
+
+
+;;;; User Interface -----------------------------------------------------------
+(defmacro defparameters (parameters values-form)
+  `(progn
+     ,@(loop :for parameter :in parameters
+             :collect `(defparameter ,parameter nil))
+     (setf (values ,@parameters) ,values-form)
+     ',parameters))
+
+(defun make-boolean-options
+    (name &key
+     (name-no (intern (concatenate 'string (string 'no-) (string name))))
+     long
+     (long-no (when long (format nil "no-~A" long)))
+     short
+     (short-no (when short (char-upcase short)))
+     (result-key name)
+     help
+     help-no
+     manual
+     manual-no
+     initial-value)
+  (values (adopt:make-option name
+            :result-key result-key
+            :long long
+            :short short
+            :help help
+            :manual manual
+            :initial-value initial-value
+            :reduce (constantly t))
+          (adopt:make-option name-no
+            :result-key result-key
+            :long long-no
+            :short short-no
+            :help help-no
+            :manual manual-no
+            :reduce (constantly nil))))
+
+
+(defparameters (*option-debug* *option-no-debug*)
+  (make-boolean-options 'debug
+    :long "debug"
+    :short #\d
+    :help "Enable the Lisp debugger."
+    :help-no "Disable the Lisp debugger (default)."))
+
+(defparameter *option-help*
+  (adopt:make-option 'help
+    :help "Display help and exit."
+    :long "help"
+    :short #\h
+    :reduce (constantly t)))
+
+(defparameter *option-version*
+  (adopt:make-option 'version
+    :help "Display version information and exit."
+    :long "version"
+    :reduce (constantly t)))
+
+
+(defparameter *option-one-based*
+  (adopt:make-option 'one-based
+    :result-key 'index-base
+    :help "Start numbering lines at 1 (default)."
+    :short #\1
+    :long "one"
+    :reduce (constantly 1)))
+
+(defparameter *option-zero-based*
+  (adopt:make-option 'zero-based
+    :result-key 'index-base
+    :help "Start numbering lines at 0."
+    :short #\0
+    :long "zero"
+    :reduce (constantly 0)))
+
+(defparameter *option-other-base*
+  (adopt:make-option 'other-base
+    :result-key 'index-base
+    :initial-value 0
+    :help "Start numbering lines at N."
+    :parameter "N"
+    :short #\s
+    :long "start"
+    :key #'parse-integer
+    :reduce #'adopt:last))
+
+(defparameters (*option-include-numbers* *option-no-include-numbers*)
+  (make-boolean-options 'include-numbers
+    :long "number"
+    :short #\n
+    :help "Add line numbers to the output."
+    :help-no "Do not add line number to the output (default)."))
+
+
+(defparameter *option-limit*
+  (adopt:make-option 'limit
+    :help "Read at most N lines."
+    :parameter "N"
+    :short #\l
+    :long "limit"
+    :key #'parse-integer
+    :reduce #'adopt:last))
+
+(defparameter *option-no-limit*
+  (adopt:make-option 'no-limit
+    :result-key 'limit
+    :help "Read all lines (default)."
+    :short #\L
+    :long "no-limit"
+    :reduce (constantly nil)))
+
+
+(defparameter *option-input-encoding*
+  (adopt:make-option 'input-encoding
+    :help "Treat input as being encoded with ENC (default utf-8)."
+    :parameter "ENC"
+    :short #\i
+    :long "input-encoding"
+    :initial-value "utf-8"
+    :reduce #'adopt:last))
+
+(defparameter *option-output-encoding*
+  (adopt:make-option 'output-encoding
+    :help "Output text encoded with ENC (default utf-8)."
+    :parameter "ENC"
+    :short #\o
+    :long "output-encoding"
+    :initial-value "utf-8"
+    :reduce #'adopt:last))
+
+(defparameter *option-input-replacement*
+  (adopt:make-option 'input-replacement
+    :help "If an input character is not valid in the selected encoding, replace it with REP."
+    :parameter "REP"
+    :short #\r
+    :long "input-replacement"
+    :reduce #'adopt:last))
+
+(defparameter *option-no-input-replacement*
+  (adopt:make-option 'no-input-replacement
+    :result-key 'input-replacement
+    :help "If an input character is not valid in the selected encoding, return an error (default)."
+    :short #\R
+    :long "no-input-replacement"
+    :reduce (constantly nil)))
+
+(defparameter *option-output-replacement*
+  (adopt:make-option 'output-replacement
+    :help "If an output character would not be not valid in the selected encoding, replace it with REP."
+    :parameter "REP"
+    :short #\q
+    :long "output-replacement"
+    :reduce #'adopt:last))
+
+(defparameter *option-no-output-replacement*
+  (adopt:make-option 'no-output-replacement
+    :result-key 'output-replacement
+    :help "If an output character would not be valid in the selected encoding, return an error (default)."
+    :short #\Q
+    :long "no-output-replacement"
+    :reduce (constantly nil)))
+
+
+(adopt:define-string *help-text*
+  "lines takes a string denoting which lines to print, and prints those lines ~
+   of standard input.")
+
+(defparameter *examples*
+  '(("Print line 1234:"
+     . "cat log.txt | lines 1234")
+    ("Print line 2, then line 1:"
+     . "cat log.txt | lines 2,1")
+    ("Print lines 6, 12, 100-200, and 999+ (1-indexed):"
+     . "cat log.txt | lines -1 6,12,100-200,999-")
+    ("Print lines 0, 2, 4, 6, …:"
+     . "cat log.txt | lines m2")
+    ("Print the third line of every set of four lines:"
+     . "cat foo.fastq | lines 3m4")))
+
+
+(defparameter *ui*
+  (adopt:make-interface
+    :name "lines"
+    :usage "[OPTIONS] LINE-DESIGNATORS"
+    :summary "print designated lines of standard input"
+    :help *help-text*
+    :examples *examples*
+    :contents (list
+                *option-limit*
+                *option-no-limit*
+                *option-help*
+                *option-version*
+                *option-debug*
+                *option-no-debug*
+                (adopt:make-group 'character-encodings
+                                  :title "Character Encodings"
+                                  :options (list
+                                             *option-input-encoding*
+                                             *option-input-replacement*
+                                             *option-no-input-replacement*
+                                             *option-output-encoding*
+                                             *option-output-replacement*
+                                             *option-no-output-replacement*))
+                (adopt:make-group 'line-numbering
+                                  :title "Line Numbering"
+                                  :options (list
+                                             *option-one-based*
+                                             *option-zero-based*
+                                             *option-other-base*
+                                             *option-include-numbers*
+                                             *option-no-include-numbers*)))))
+
+
+(defmacro without-debugger (&body body)
+  `(multiple-value-prog1
+     (progn
+       #+sbcl (sb-ext:disable-debugger)
+       (progn ,@body))
+     (progn
+       #+sbcl (sb-ext:enable-debugger))))
+
+(defmacro exit-on-error (&body body)
+  `(without-debugger
+     (handler-case (progn ,@body)
+       #+sbcl (sb-int:broken-pipe () (adopt:exit))
+       (error (c) (adopt:print-error-and-exit c)))))
+
+(defmacro exit-on-error-unless (expr &body body)
+  `(if ,expr
+     (progn ,@body)
+     (exit-on-error ,@body)))
+
+(defmacro exit-on-ctrl-c (&body body)
+  `(handler-case
+       (with-user-abort:with-user-abort (progn ,@body))
+     (with-user-abort:user-abort () (adopt:exit 130))))
+
+
+(defun determine-external-format (encoding replacement)
+  (let ((encoding (intern (string-upcase encoding) :keyword)))
+    (if (null replacement)
+      encoding
+      (list encoding :replacement replacement))))
+
+(defun toplevel ()
+  (exit-on-ctrl-c
+    (multiple-value-bind (arguments options) (adopt:parse-options-or-exit *ui*)
+      (exit-on-error-unless (gethash 'debug options)
+        (cond
+          ((gethash 'help options) (adopt:print-help-and-exit *ui*))
+          ((gethash 'version options) (write-line *version*) (adopt:exit))
+          ((null arguments) (error "LINE-DESIGNATORS are required."))
+          (t (destructuring-bind (line-designators . more) arguments
+               (when more
+                 (error "Unrecognized command line arguments: ~S" more))
+               (let ((*index-base* (gethash 'index-base options))
+                     (*include-numbers* (gethash 'include-numbers options))
+                     (*limit* (gethash 'limit options))
+                     (input-format (determine-external-format
+                                     (gethash 'input-encoding options)
+                                     (gethash 'input-replacement options)))
+                     (output-format (determine-external-format
+                                      (gethash 'output-encoding options)
+                                      (gethash 'output-replacement options))))
+                 (with-open-file (*standard-input* "/dev/stdin"
+                                                   :external-format input-format)
+                   (with-open-file (*standard-output* "/dev/stdout"
+                                                      :external-format output-format
+                                                      :direction :output
+                                                      :if-exists :append)
+                     (run line-designators)))))))))))
+
+
+#; Scratch --------------------------------------------------------------------
+
+(let ((*standard-input* (make-string-input-stream
+"0 a foo
+1 b bar
+2 c baz
+3 d hello
+4 a world
+5 b yes
+6 c this
+7 d is
+8 a cat
+9 b meow")))
+  (run "4m4"))
--- a/psqlrc	Tue Feb 04 09:23:46 2020 -0500
+++ b/psqlrc	Tue Feb 04 09:24:12 2020 -0500
@@ -7,3 +7,6 @@
 
 \set PROMPT1 '%[%033[1;34m%]%M:%> %n@%/%R%#%x%[%033[0m%] '
 \timing
+
+\setenv PAGER less
+\setenv LESS -iS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remote/bin/e	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,1 @@
+../../bin/e
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remote/bin/lines	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,1 @@
+../../lisp/bin/lines
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remote/bin/u	Tue Feb 04 09:24:12 2020 -0500
@@ -0,0 +1,1 @@
+../../bin/u
\ No newline at end of file
--- a/restic/excludes.txt	Tue Feb 04 09:23:46 2020 -0500
+++ b/restic/excludes.txt	Tue Feb 04 09:24:12 2020 -0500
@@ -1,20 +1,31 @@
+*.fasl
 .cache
-cache2
+/home/sjl/.arduino15
+/home/sjl/.config/chromium
+/home/sjl/.config/discord
+/home/sjl/.config/google-chrome
+/home/sjl/.config/libreoffice
+/home/sjl/.config/unity3d
+/home/sjl/.crawl
 /home/sjl/.dbus
-/home/sjl/src/dotfiles/vim/tmp
-/home/sjl/snap
+/home/sjl/.dropbox
+/home/sjl/.dropbox-dist
+/home/sjl/.gimp-*
+/home/sjl/.go
+/home/sjl/.hg-git
+/home/sjl/.local/lib/python*
+/home/sjl/.local/share
+/home/sjl/.mozilla
+/home/sjl/.quicklisp
+/home/sjl/.rlwrap
+/home/sjl/.slime
+/home/sjl/.steam
+/home/sjl/.virtualenvs
+/home/sjl/Dropbox/.dropbox.cache
 /home/sjl/Videos
 /home/sjl/dwhelper
-/home/sjl/.mozilla
-/home/sjl/.dropbox
-/home/sjl/.steam
-/home/sjl/.quicklisp
-/home/sjl/.virtualenvs
-/home/sjl/.local/share
-/home/sjl/.local/lib/python*
-/home/sjl/.config/chromium
-/home/sjl/.config/libreoffice
-/home/sjl/.config/discord
-/home/sjl/.dropbox-dist
-/home/sjl/Dropbox/.dropbox.cache
-
+/home/sjl/snap
+/home/sjl/src/abcl
+/home/sjl/src/arduino
+/home/sjl/src/dotfiles/vim/tmp
+cache2
--- a/servers/bash_profile	Tue Feb 04 09:23:46 2020 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-#!/usr/bin/env bash
-
-shopt -s expand_aliases
-
-export PATH=~/bin:~/dotfiles/bin:$PATH
-
-alias l='ls -1 --color=auto'
-alias ll='ls -la1 --color=auto'
-alias h='hg'
-alias g='git'
-alias pj='python -m json.tool'
-alias ..='cd ..'
-alias ...='cd ../..'
-alias ....='cd ../../..'
-alias .....='cd ../../../..'
-alias ......='cd ../../../../..'
-alias nvim=vim
-
-function psg() {
-    ps auxww | grep --color=always $* | grep -v grep | collapse | cuts -f 2,11-
-}
-
-export EDITOR=vim
-
-D=$'\e[37m'
-PINK=$'\e[35m'
-GREEN=$'\e[32m'
-ORANGE=$'\e[33m'
-
-export PS1='\n${PINK}\u ${D}at ${ORANGE}\h ${D}in ${GREEN}\w${D}\n$ '
--- a/servers/bin/collapse	Tue Feb 04 09:23:46 2020 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-../../bin/collapse
\ No newline at end of file
--- a/servers/bin/cuts	Tue Feb 04 09:23:46 2020 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-../../bin/cuts
\ No newline at end of file
--- a/servers/bin/f	Tue Feb 04 09:23:46 2020 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-../../bin/f
\ No newline at end of file
--- a/vim/custom-dictionary.utf-8.add	Tue Feb 04 09:23:46 2020 -0500
+++ b/vim/custom-dictionary.utf-8.add	Tue Feb 04 09:24:12 2020 -0500
@@ -299,3 +299,7 @@
 Phosphorylation
 iterate's
 memoization
+gnuplot
+Illumina
+Phred
+FastQC
--- a/vim/vimrc	Tue Feb 04 09:23:46 2020 -0500
+++ b/vim/vimrc	Tue Feb 04 09:24:12 2020 -0500
@@ -1405,7 +1405,7 @@
 augroup ft_gnuplot
     au!
 
-    au BufNewFile,BufRead *.gp setlocal filetype=gnuplot
+    au BufNewFile,BufRead *.gp,.gnuplot setlocal filetype=gnuplot
 
     au FileType gnuplot nnoremap <buffer> <silent> <localleader>o :call OpenGnuplotRepl()<cr>
 
@@ -1627,6 +1627,7 @@
     au!
 
     au Filetype make setlocal shiftwidth=8
+    au Filetype make setlocal foldmethod=marker foldmarker={{{,}}}
 augroup END
 
 " }}}
@@ -1790,7 +1791,7 @@
     au BufNewFile,BufRead *.sql set filetype=pgsql
     au BufNewFile,BufRead *.pgsql set filetype=pgsql
 
-    au FileType pgsql set foldmethod=indent
+    au FileType pgsql set foldmethod=marker foldmarker=\ $$,$$\ 
     au FileType pgsql set softtabstop=2 shiftwidth=2
     au FileType pgsql setlocal commentstring=--\ %s comments=:--