about summary refs log tree commit diff
path: root/emacs/.emacs.d/wpc
diff options
context:
space:
mode:
authorWilliam Carroll <wpcarro@gmail.com>2020-01-30T16·00+0000
committerWilliam Carroll <wpcarro@gmail.com>2020-01-30T16·00+0000
commit578ed1ba98510058cf48f897a9bf4e3391684120 (patch)
tree5eadabd3d232151c75ac2424eaa8771ab25e927e /emacs/.emacs.d/wpc
parent3684adf23f847114e1beeaab162398628ba571aa (diff)
Move move .emacs.d out of configs/shared
Moving all of my Emacs-related files into their own directory at the root of
this repository.
Diffstat (limited to 'emacs/.emacs.d/wpc')
-rw-r--r--emacs/.emacs.d/wpc/alist.el277
-rw-r--r--emacs/.emacs.d/wpc/bag.el66
-rw-r--r--emacs/.emacs.d/wpc/bills.el26
-rw-r--r--emacs/.emacs.d/wpc/bookmark.el145
-rw-r--r--emacs/.emacs.d/wpc/buffer.el198
-rw-r--r--emacs/.emacs.d/wpc/bytes.el109
-rw-r--r--emacs/.emacs.d/wpc/cache.el80
-rw-r--r--emacs/.emacs.d/wpc/chrome.el82
-rw-r--r--emacs/.emacs.d/wpc/clipboard.el44
-rw-r--r--emacs/.emacs.d/wpc/colorscheme.el96
-rw-r--r--emacs/.emacs.d/wpc/constants.el41
-rw-r--r--emacs/.emacs.d/wpc/cycle.el155
-rw-r--r--emacs/.emacs.d/wpc/device.el38
-rw-r--r--emacs/.emacs.d/wpc/display.el98
-rw-r--r--emacs/.emacs.d/wpc/do.el54
-rw-r--r--emacs/.emacs.d/wpc/dotfiles.el53
-rw-r--r--emacs/.emacs.d/wpc/dotted.el49
-rw-r--r--emacs/.emacs.d/wpc/email.el11
-rw-r--r--emacs/.emacs.d/wpc/entr.el115
-rw-r--r--emacs/.emacs.d/wpc/enum.el98
-rw-r--r--emacs/.emacs.d/wpc/finance.el119
-rw-r--r--emacs/.emacs.d/wpc/fonts.el153
-rw-r--r--emacs/.emacs.d/wpc/fs.el65
-rw-r--r--emacs/.emacs.d/wpc/functions.el133
-rw-r--r--emacs/.emacs.d/wpc/graph.el91
-rw-r--r--emacs/.emacs.d/wpc/imdb.el128
-rw-r--r--emacs/.emacs.d/wpc/irc.el177
-rw-r--r--emacs/.emacs.d/wpc/iso.el95
-rw-r--r--emacs/.emacs.d/wpc/ivy-clipmenu.el134
-rw-r--r--emacs/.emacs.d/wpc/ivy-helpers.el31
-rw-r--r--emacs/.emacs.d/wpc/kaomoji.el45
-rw-r--r--emacs/.emacs.d/wpc/kbd.el90
-rw-r--r--emacs/.emacs.d/wpc/keybindings.el46
-rw-r--r--emacs/.emacs.d/wpc/keyboard.el152
-rw-r--r--emacs/.emacs.d/wpc/keymap.el25
-rw-r--r--emacs/.emacs.d/wpc/laptop-battery.el60
-rw-r--r--emacs/.emacs.d/wpc/list.el235
-rw-r--r--emacs/.emacs.d/wpc/list.nix8
-rw-r--r--emacs/.emacs.d/wpc/macros.el95
-rw-r--r--emacs/.emacs.d/wpc/math.el59
-rw-r--r--emacs/.emacs.d/wpc/maybe.el102
-rw-r--r--emacs/.emacs.d/wpc/me-seconds.el245
-rw-r--r--emacs/.emacs.d/wpc/monoid.el30
-rw-r--r--emacs/.emacs.d/wpc/number.el153
-rw-r--r--emacs/.emacs.d/wpc/org-helpers.el29
-rw-r--r--emacs/.emacs.d/wpc/playback.el41
-rw-r--r--emacs/.emacs.d/wpc/polymorphism.el37
-rw-r--r--emacs/.emacs.d/wpc/prelude.el149
-rw-r--r--emacs/.emacs.d/wpc/prelude.nix11
-rw-r--r--emacs/.emacs.d/wpc/pulse-audio.el66
-rw-r--r--emacs/.emacs.d/wpc/pushover.el75
-rw-r--r--emacs/.emacs.d/wpc/random.el73
-rw-r--r--emacs/.emacs.d/wpc/region.el20
-rw-r--r--emacs/.emacs.d/wpc/scheduler.el22
-rw-r--r--emacs/.emacs.d/wpc/scope.el99
-rw-r--r--emacs/.emacs.d/wpc/screen-brightness.el45
-rw-r--r--emacs/.emacs.d/wpc/scrot.el64
-rw-r--r--emacs/.emacs.d/wpc/sequence.el105
-rw-r--r--emacs/.emacs.d/wpc/series.el89
-rw-r--r--emacs/.emacs.d/wpc/set.el171
-rw-r--r--emacs/.emacs.d/wpc/ssh.el31
-rw-r--r--emacs/.emacs.d/wpc/stack.el93
-rw-r--r--emacs/.emacs.d/wpc/string.el128
-rw-r--r--emacs/.emacs.d/wpc/string.nix8
-rw-r--r--emacs/.emacs.d/wpc/struct.el88
-rw-r--r--emacs/.emacs.d/wpc/symbol.el43
-rw-r--r--emacs/.emacs.d/wpc/terminator-themes.json1794
-rw-r--r--emacs/.emacs.d/wpc/terminator.el94
-rw-r--r--emacs/.emacs.d/wpc/themes.el204
-rw-r--r--emacs/.emacs.d/wpc/todo.el293
-rw-r--r--emacs/.emacs.d/wpc/tree.el193
-rw-r--r--emacs/.emacs.d/wpc/tuple.el86
-rw-r--r--emacs/.emacs.d/wpc/vector.el81
-rw-r--r--emacs/.emacs.d/wpc/wallpaper.el92
-rw-r--r--emacs/.emacs.d/wpc/window-manager.el647
-rw-r--r--emacs/.emacs.d/wpc/window.el37
-rw-r--r--emacs/.emacs.d/wpc/wpc-clojure.el85
-rw-r--r--emacs/.emacs.d/wpc/wpc-company.el28
-rw-r--r--emacs/.emacs.d/wpc/wpc-dired.el41
-rw-r--r--emacs/.emacs.d/wpc/wpc-docker.el16
-rw-r--r--emacs/.emacs.d/wpc/wpc-elixir.el13
-rw-r--r--emacs/.emacs.d/wpc/wpc-flycheck.el14
-rw-r--r--emacs/.emacs.d/wpc/wpc-haskell.el56
-rw-r--r--emacs/.emacs.d/wpc/wpc-java.el42
-rw-r--r--emacs/.emacs.d/wpc/wpc-javascript.el83
-rw-r--r--emacs/.emacs.d/wpc/wpc-keybindings.el229
-rw-r--r--emacs/.emacs.d/wpc/wpc-lisp.el111
-rw-r--r--emacs/.emacs.d/wpc/wpc-misc.el248
-rw-r--r--emacs/.emacs.d/wpc/wpc-nix.el56
-rw-r--r--emacs/.emacs.d/wpc/wpc-ocaml.el43
-rw-r--r--emacs/.emacs.d/wpc/wpc-org.el70
-rw-r--r--emacs/.emacs.d/wpc/wpc-package.el27
-rw-r--r--emacs/.emacs.d/wpc/wpc-prolog.el16
-rw-r--r--emacs/.emacs.d/wpc/wpc-python.el21
-rw-r--r--emacs/.emacs.d/wpc/wpc-reasonml.el29
-rw-r--r--emacs/.emacs.d/wpc/wpc-rust.el34
-rw-r--r--emacs/.emacs.d/wpc/wpc-shell.el17
-rw-r--r--emacs/.emacs.d/wpc/wpc-terminal.el70
-rw-r--r--emacs/.emacs.d/wpc/wpc-ui.el179
-rw-r--r--emacs/.emacs.d/wpc/wpgtk.el45
-rw-r--r--emacs/.emacs.d/wpc/ynab.el56
-rw-r--r--emacs/.emacs.d/wpc/zle.el90
102 files changed, 11033 insertions, 0 deletions
diff --git a/emacs/.emacs.d/wpc/alist.el b/emacs/.emacs.d/wpc/alist.el
new file mode 100644
index 000000000000..f23109ce6a38
--- /dev/null
+++ b/emacs/.emacs.d/wpc/alist.el
@@ -0,0 +1,277 @@
+;;; alist.el --- Interface for working with associative lists -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Firstly, a rant:
+;; In most cases, I find Elisp's APIs to be confusing.  There's a mixture of
+;; overloaded functions that leak the implementation details (TODO: provide an
+;; example of this.) of the abstract data type, which I find privileges those
+;; "insiders" who spend disproportionately large amounts of time in Elisp land,
+;; and other functions with little-to-no pattern about the order in which
+;; arguments should be applied.  In theory, however, most of these APIs could
+;; and should be much simpler.  This module represents a step in that direction.
+;;
+;; I'm modelling these APIs after Elixir's APIs.
+;;
+;; On my wishlist is to create protocols that will allow generic interfaces like
+;; Enum protocols, etc.  Would be nice to abstract over...
+;; - associative lists (i.e. alists)
+;; - property lists (i.e. plists)
+;; - hash tables
+;; ...with some dictionary or map-like interface.  This will probably end up
+;; being quite similar to the kv.el project but with differences at the API
+;; layer.
+;;
+;; Similar libraries:
+;; - map.el: Comes bundled with recent versions of Emacs.
+;; - asoc.el: Helpers for working with alists.  asoc.el is similar to alist.el
+;;   because it uses the "!" convention for signalling that a function mutates
+;;   the underlying data structure.
+;; - ht.el: Hash table library.
+;; - kv.el: Library for dealing with key-value collections.  Note that map.el
+;;   has a similar typeclass because it works with lists, hash-tables, or
+;;   arrays.
+;; - a.el: Clojure-inspired way of working with key-value data structures in
+;; Elisp.  Works with alists, hash-tables, and sometimes vectors.
+;;
+;; Some API design principles:
+;; - The "noun" (i.e. alist) of the "verb" (i.e. function) comes last to improve
+;; composability with the threading macro (i.e. `->>') and to improve consumers'
+;; intuition with the APIs.  Learn this once, know it always.
+;;
+;; - Every function avoids mutating the alist unless it ends with !.
+;;
+;; - CRUD operations will be named according to the following table:
+;;   - "create" *and* "set"
+;;   - "read"   *and* "get"
+;;   - "update"
+;;   - "delete" *and* "remove"
+;;
+;; For better or worse, all of this code expects alists in the form of:
+;; ((first-name . "William") (last-name . "Carroll"))
+;;
+;; Special thanks to github.com/alphapapa/emacs-package-dev-handbook for some of
+;; the idiomatic ways to update alists.
+;;
+;; TODO: Include a section that compares alist.el to a.el from
+;; github.com/plexus/a.el.
+
+;; Dependencies:
+
+;; TODO: Consider dropping explicit dependency white-listing since all of these
+;; should be available in my Emacs.  The problem arises when this library needs
+;; to be published, in which case, something like Nix and a build process could
+;; possible insert the necessary require statements herein.  Not sure how I feel
+;; about this though.
+(require 'maybe)
+(require 'macros)
+(require 'dash)
+(require 'tuple)
+(require 'maybe)
+
+;;; Code:
+
+;; TODO: Support function aliases for:
+;; - create/set
+;; - read/get
+;; - update
+;; - delete/remove
+
+;; Support mutative variants of functions with an ! appendage to their name.
+
+;; Ensure that the same message about only updating the first occurrence of a
+;; key is consistent throughout documentation using string interpolation or some
+;; other mechanism.
+
+;; TODO: Consider wrapping all of this with `(cl-defstruct alist xs)'.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst alist/enable-tests? t
+  "When t, run the test suite.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Support a variadic version of this to easily construct alists.
+(defun alist/new ()
+  "Return a new, empty alist."
+  '())
+
+;; Create
+;; TODO: See if this mutates.
+(defun alist/set (k v xs)
+  "Set K to V in XS."
+  (if (alist/has-key? k xs)
+      (progn
+        (setf (alist-get k xs) v)
+        xs)
+    (list/cons `(,k . ,v) xs)))
+
+(defun alist/set! (k v xs)
+  "Set K to V in XS mutatively.
+Note that this doesn't append to the alist in the way that most alists handle
+  writing.  If the k already exists in XS, it is overwritten."
+  (map-delete xs k)
+  (map-put xs k v))
+
+;; Read
+(defun alist/get (k xs)
+  "Return the value at K in XS; otherwise, return nil.
+Returns the first occurrence of K in XS since alists support multiple entries."
+  (cdr (assoc k xs)))
+
+(defun alist/get-entry (k xs)
+  "Return the first key-value pair at K in XS."
+  (assoc k xs))
+
+;; Update
+;; TODO: Add warning about only the first occurrence being updated in the
+;; documentation.
+(defun alist/update (k f xs)
+  "Apply F to the value stored at K in XS.
+If `K' is not in `XS', this function errors.  Use `alist/upsert' if you're
+interested in inserting a value when a key doesn't already exist."
+  (if (maybe/nil? (alist/get k xs))
+      (error "Refusing to update: key does not exist in alist")
+    (alist/set k (funcall f (alist/get k xs)) xs)))
+
+(defun alist/update! (k f xs)
+  "Call F on the entry at K in XS.
+Mutative variant of `alist/update'."
+  (alist/set! k (funcall f (alist/get k xs))xs))
+
+;; TODO: Support this.
+(defun alist/upsert (k v f xs)
+  "If K exists in `XS' call `F' on the value otherwise insert `V'."
+  (if (alist/get k xs)
+      (alist/update k f xs)
+    (alist/set k v xs)))
+
+;; Delete
+;; TODO: Make sure `delete' and `remove' behave as advertised in the Elisp docs.
+(defun alist/delete (k xs)
+  "Deletes the entry of K from XS.
+This only removes the first occurrence of K, since alists support multiple
+  key-value entries.  See `alist/delete-all' and `alist/dedupe'."
+  (remove (assoc k xs) xs))
+
+(defun alist/delete! (k xs)
+  "Delete the entry of K from XS.
+Mutative variant of `alist/delete'."
+  (delete (assoc k xs) xs))
+
+;; Additions to the CRUD API
+;; TODO: Implement this function.
+(defun alist/dedupe-keys (xs)
+  "Remove the entries in XS where the keys are `equal'.")
+
+(defun alist/dedupe-entries (xs)
+  "Remove the entries in XS where the key-value pair are `equal'."
+  (delete-dups xs))
+
+(defun alist/keys (xs)
+  "Return a list of the keys in XS."
+  (mapcar 'car xs))
+
+(defun alist/values (xs)
+  "Return a list of the values in XS."
+  (mapcar 'cdr xs))
+
+(defun alist/has-key? (k xs)
+  "Return t if XS has a key `equal' to K."
+  (maybe/some? (assoc k xs)))
+
+(defun alist/has-value? (v xs)
+  "Return t if XS has a value of V."
+  (maybe/some? (rassoc v xs)))
+
+(defun alist/count (xs)
+  "Return the number of entries in XS."
+  (length xs))
+
+;; TODO: Should I support `alist/find-key' and `alist/find-value' variants?
+(defun alist/find (p xs)
+  "Apply a predicate fn, P, to each key and value in XS and return the key of
+  the first element that returns t."
+  (let ((result (list/find (lambda (x) (funcall p (car x) (cdr x))) xs)))
+    (if result
+        (car result)
+      nil)))
+
+(defun alist/map-keys (f xs)
+  "Call F on the values in XS, returning a new alist."
+  (list/map (lambda (x)
+              `(,(funcall f (car x)) . ,(cdr x)))
+            xs))
+
+(defun alist/map-values (f xs)
+  "Call F on the values in XS, returning a new alist."
+  (list/map (lambda (x)
+              `(,(car x) . ,(funcall f (cdr x))))
+            xs))
+
+(defun alist/reduce (acc f xs)
+  "Return a new alist by calling F on k v and ACC from XS.
+F should return a tuple.  See tuple.el for more information."
+  (->> (alist/keys xs)
+       (list/reduce acc
+                    (lambda (k acc)
+                      (funcall f k (alist/get k xs) acc)))))
+
+(defun alist/merge (a b)
+  "Return a new alist with a merge of alists, A and B.
+In this case, the last writer wins, which is B."
+  (alist/reduce a #'alist/set b))
+
+;; TODO: Support `-all' variants like:
+;; - get-all
+;; - delete-all
+;; - update-all
+
+;; Scratch-pad
+(macros/comment
+ (progn
+   (setq person '((first-name . "William")
+                  (first-name . "William")
+                  (last-name  . "Carroll")
+                  (last-name  . "Another")))
+   (alist/set 'last-name "Van Gogh" person)
+   (alist/get 'last-name person)
+   (alist/update 'last-name (lambda (x) "whoops") person)
+   (alist/delete 'first-name person)
+   (alist/keys person)
+   (alist/values person)
+   (alist/count person)
+   (alist/has-key? 'first-name person)
+   (alist/has-value? "William" person)
+   ;; (alist/dedupe-keys person)
+   (alist/dedupe-entries person)
+   (alist/count person)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when alist/enable-tests?
+  (prelude/assert
+   (equal '((2 . one)
+            (3 . two))
+          (alist/map-keys #'1+
+                          '((1 . one)
+                            (2 . two)))))
+  (prelude/assert
+   (equal '((one . 2)
+            (two . 3))
+          (alist/map-values #'1+
+                            '((one . 1)
+                              (two . 2))))))
+
+
+;; TODO: Support test cases for the entire API.
+
+(provide 'alist)
+;;; alist.el ends here
diff --git a/emacs/.emacs.d/wpc/bag.el b/emacs/.emacs.d/wpc/bag.el
new file mode 100644
index 000000000000..c9511b18e737
--- /dev/null
+++ b/emacs/.emacs.d/wpc/bag.el
@@ -0,0 +1,66 @@
+;;; bag.el --- Working with bags (aka multi-sets) -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; What is a bag?  A bag should be thought of as a frequency table.  It's a way
+;; to convert a list of something into a set that allows duplicates.  Isn't
+;; allowing duplicates the whole thing with Sets?  Kind of.  But the interface
+;; of Sets is something that bags resemble, so multi-set isn't as bag of a name
+;; as it may first seem.
+;;
+;; If you've used Python's collections.Counter, the concept of a bag should be
+;; familiar already.
+;;
+;; Interface:
+;; - add        :: x -> Bag(x) -> Bag(x)
+;; - remove     :: x -> Bag(x) -> Bag(x)
+;; - union      :: Bag(x) -> Bag(x) -> Bag(x)
+;; - difference :: Bag(x) -> Bag(x) -> Bag(x)
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'number)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defstruct bag xs)
+
+(defun bag/update (f xs)
+  "Call F on alist in XS."
+  (let ((ys (bag-xs xs)))
+    (setf (bag-xs xs) (funcall f ys))))
+
+(defun bag/new ()
+  "Create an empty bag."
+  (make-bag :xs (alist/new)))
+
+(defun bag/contains? (x xs)
+  "Return t if XS has X."
+  (alist/has-key? x (bag-xs xs)))
+
+;; TODO: Tabling this for now since working with structs seems to be
+;; disappointingly difficult.  Where is `struct/update'?
+;; (defun bag/add (x xs)
+;;   "Add X to XS.")
+
+;; TODO: What do we name delete vs. remove?
+;; (defun bag/remove (x xs)
+;;   "Remove X from XS.
+;; This is a no-op is X doesn't exist in XS.")
+
+(defun bag/from-list (xs)
+  "Map a list of `XS' into a bag."
+  (->> xs
+       (list/reduce
+        (bag/new)
+        (lambda (x acc)
+          (bag/add x 1 #'number/inc acc)))))
+
+(provide 'bag)
+;;; bag.el ends here
diff --git a/emacs/.emacs.d/wpc/bills.el b/emacs/.emacs.d/wpc/bills.el
new file mode 100644
index 000000000000..fbdeb9d0f820
--- /dev/null
+++ b/emacs/.emacs.d/wpc/bills.el
@@ -0,0 +1,26 @@
+;;; bills.el --- Helping me manage my bills -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; For personal use only.
+
+;;; Code:
+
+(defconst bills/whitelist '(("Council Tax" . "rbkc.gov.uk/onlinepayments/counciltaxpayments/")
+                            ("Internet". "plus.net/member-centre/login"))
+  "Maps searchable labels to URLs to pay these bills.")
+
+(defun bills/url ()
+  "Copies the URL to pay a bill onto the clipboard."
+  (ivy-read
+   "Bill: "
+   bills/whitelist
+   :action (lambda (entry)
+             (kill-new (cdr entry))
+             (alert "Copied to clipboard!"))))
+
+(macros/comment
+ (bills/url))
+
+(provide 'bills)
+;;; bills.el ends here
diff --git a/emacs/.emacs.d/wpc/bookmark.el b/emacs/.emacs.d/wpc/bookmark.el
new file mode 100644
index 000000000000..734ddaa13a27
--- /dev/null
+++ b/emacs/.emacs.d/wpc/bookmark.el
@@ -0,0 +1,145 @@
+;;; bookmark.el --- Saved files and directories on my filesystem -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; After enjoying and relying on Emacs's builtin `jump-to-register' command, I'd
+;; like to recreate this functionality with a few extensions.
+;;
+;; Everything herein will mimmick my previous KBDs for `jump-to-register', which
+;; were <leader>-j-<register-kbd>.  If the `bookmark-path' is a file, Emacs will
+;; open a buffer with that file.  If the `bookmark-path' is a directory, Emacs
+;; will open an ivy window searching that directory.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'f)
+(require 'buffer)
+(require 'list)
+(require 'string)
+(require 'set)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defstruct bookmark label path kbd)
+
+(defconst bookmark/install-kbds? t
+  "When t, install keybindings.")
+
+;; TODO: Consider hosting this function somewhere other than here, since it
+;; feels useful above of the context of bookmarks.
+;; TODO: Assess whether it'd be better to use the existing function:
+;; `counsel-projectile-switch-project-action'.  See the noise I made on GH for
+;; more context: https://github.com/ericdanan/counsel-projectile/issues/137
+
+(defun bookmark/handle-directory-dwim (path)
+  "Open PATH as either a project directory or a regular directory.
+If PATH is `projectile-project-p', open with `counsel-projectile-find-file'.
+Otherwise, open with `counsel-find-file'."
+  (if (projectile-project-p path)
+      (with-temp-buffer
+        (cd (projectile-project-p path))
+        (call-interactively #'counsel-projectile-find-file))
+    (let ((ivy-extra-directories nil))
+      (counsel-find-file path))))
+
+(defconst bookmark/handle-directory #'bookmark/handle-directory-dwim
+  "Function to call when a bookmark points to a directory.")
+
+(defconst bookmark/handle-file #'counsel-find-file-action
+  "Function to call when a bookmark points to a file.")
+
+(defconst bookmark/whitelist
+  (list
+   (make-bookmark :label "depot"
+                  :path "~/depot"
+                  :kbd "t")
+   (make-bookmark :label "org"
+                  :path "~/Dropbox/org"
+                  :kbd "o")
+   (make-bookmark :label "universe"
+                  :path "~/universe"
+                  :kbd "m")
+   (make-bookmark :label "dotfiles"
+                  :path "~/dotfiles"
+                  :kbd "d")
+   (make-bookmark :label "current project"
+                  :path constants/current-project
+                  :kbd "p"))
+  "List of registered bookmarks.")
+
+(defun bookmark/from-label (label)
+  "Return the bookmark with LABEL or nil."
+  (->> bookmark/whitelist
+       (list/find (lambda (b) (equal label (bookmark-label b))))))
+
+(defun bookmark/magit-status ()
+  "Use ivy to select a bookmark and jump to its `magit-status' buffer."
+  (interactive)
+  (let ((labels (set/new "dotfiles" "universe" "depot"))
+        (all-labels (->> bookmark/whitelist
+                         (list/map (>> bookmark-label))
+                         set/from-list)))
+    (prelude/assert (set/subset? labels all-labels))
+    (ivy-read "Repository: "
+              (set/to-list labels)
+              :require-match t
+              :action (lambda (label)
+                        (->> label
+                             bookmark/from-label
+                             bookmark-path
+                             magit-status)))))
+
+;; TODO: Consider `ivy-read' extension that takes a list of structs,
+;; `struct-to-label' and `label-struct' functions.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; API
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun bookmark/open (b)
+  "Open bookmark, B, in a new buffer or an ivy minibuffer."
+  (let ((path (bookmark-path b)))
+    (cond
+     ((f-directory? path)
+      (funcall bookmark/handle-directory path))
+     ((f-file? path)
+      (funcall bookmark/handle-file path)))))
+
+(defun bookmark/ivy-open ()
+  "Use ivy to filter available bookmarks."
+  (interactive)
+  (ivy-read "Bookmark: "
+            (->> bookmark/whitelist
+                 (list/map #'bookmark-label))
+            :require-match t
+            :action (lambda (label)
+                      (bookmark/open (bookmark/from-label label)))))
+
+(when bookmark/install-kbds?
+  (general-define-key
+   :prefix "<SPC>"
+   :states '(normal)
+   "jj" #'bookmark/ivy-open)
+  (->> bookmark/whitelist
+       (list/map
+        (lambda (b)
+          (general-define-key
+           :prefix "<SPC>"
+           :states '(normal)
+           (string/concat "j" (bookmark-kbd b))
+           ;; TODO: Consider `cl-labels' so `which-key' minibuffer is more
+           ;; helpful.
+           (lambda () (interactive) (bookmark/open b))))))
+  (general-define-key
+   :states '(normal)
+   :prefix "<SPC>"
+   "gS" #'bookmark/magit-status))
+
+(provide 'bookmark)
+;;; bookmark.el ends here
diff --git a/emacs/.emacs.d/wpc/buffer.el b/emacs/.emacs.d/wpc/buffer.el
new file mode 100644
index 000000000000..d388818e58a4
--- /dev/null
+++ b/emacs/.emacs.d/wpc/buffer.el
@@ -0,0 +1,198 @@
+;;; buffer.el --- Working with Emacs buffers -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Utilities for CRUDing buffers in Emacs.
+;;
+;; Many of these functions may seem unnecessary especially when you consider
+;; there implementations.  In general I believe that Elisp suffers from a
+;; library disorganization problem.  Providing simple wrapper functions that
+;; rename functions or reorder parameters is worth the effort in my opinion if
+;; it improves discoverability (via intuition) and improve composability.
+;;
+;; I support three ways for switching between what I'm calling "source code
+;; buffers":
+;; 1. Toggling previous: <SPC><SPC>
+;; 2. Using `ivy-read': <SPC>b
+;; TODO: These obscure evil KBDs. Maybe a hydra definition would be best?
+;; 3. Cycling (forwards/backwards): C-f, C-b
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'maybe)
+(require 'set)
+(require 'cycle)
+(require 'struct)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst buffer/enable-tests? t
+  "When t, run the test suite.")
+
+(defconst buffer/install-kbds? t
+  "When t, install the keybindings defined herein.")
+
+(defconst buffer/source-code-blacklist
+  (set/new 'dired-mode
+           'erc-mode
+           'magit-status-mode
+           'magit-process-mode
+           'magit-log-mode
+           'org-mode
+           'fundamental-mode)
+  "A blacklist of major-modes to ignore for listing source code buffers.")
+
+(defconst buffer/source-code-timeout 2
+  "Number of seconds to wait before invalidating the cycle.")
+
+(cl-defstruct source-code-cycle cycle last-called)
+
+(defun buffer/emacs-generated? (name)
+  "Return t if buffer, NAME, is an Emacs-generated buffer.
+Some buffers are Emacs-generated but are surrounded by whitespace."
+  (let ((trimmed (s-trim name)))
+    (and (s-starts-with? "*" trimmed))))
+
+(defun buffer/find (buffer-or-name)
+  "Find a buffer by its BUFFER-OR-NAME."
+  (get-buffer buffer-or-name))
+
+(defun buffer/major-mode (name)
+  "Return the active `major-mode' in buffer, NAME."
+  (with-current-buffer (buffer/find name)
+    major-mode))
+
+(defun buffer/source-code-buffers ()
+  "Return a list of source code buffers.
+This will ignore Emacs-generated buffers, like *Messages*.  It will also ignore
+  any buffer whose major mode is defined in `buffer/source-code-blacklist'."
+  (->> (buffer-list)
+       (list/map #'buffer-name)
+       (list/reject #'buffer/emacs-generated?)
+       (list/reject (lambda (name)
+                      (set/contains? (buffer/major-mode name)
+                                     buffer/source-code-blacklist)))))
+
+(defvar buffer/source-code-cycle-state
+  (make-source-code-cycle
+   :cycle (cycle/from-list (buffer/source-code-buffers))
+   :last-called (ts-now))
+  "State used to manage cycling between source code buffers.")
+
+(defun buffer/exists? (name)
+  "Return t if buffer, NAME, exists."
+  (maybe/some? (buffer/find name)))
+
+(defun buffer/new (name)
+  "Return a newly created buffer NAME."
+  (generate-new-buffer name))
+
+(defun buffer/find-or-create (name)
+  "Find or create buffer, NAME.
+Return a reference to that buffer."
+  (let ((x (buffer/find name)))
+    (if (maybe/some? x)
+        x
+      (buffer/new name))))
+
+;; TODO: Should this consume: `display-buffer' or `switch-to-buffer'?
+(defun buffer/show (buffer-or-name)
+  "Display the BUFFER-OR-NAME, which is either a buffer reference or its name."
+  (display-buffer buffer-or-name))
+
+;; TODO: Move this and `buffer/cycle-prev' into a separate module that
+;; encapsulates all of this behavior.
+
+(defun buffer/cycle (cycle-fn)
+  "Cycle forwards or backwards through `buffer/source-code-buffers'."
+  (let ((last-called (source-code-cycle-last-called
+                      buffer/source-code-cycle-state))
+        (cycle (source-code-cycle-cycle
+                buffer/source-code-cycle-state)))
+    (if (> (ts-diff (ts-now) last-called)
+           buffer/source-code-timeout)
+        (progn
+          (struct/set! source-code-cycle
+                       cycle
+                       (cycle/from-list (buffer/source-code-buffers))
+                       buffer/source-code-cycle-state)
+          (let ((cycle (source-code-cycle-cycle
+                        buffer/source-code-cycle-state)))
+            (funcall cycle-fn cycle)
+            (switch-to-buffer (cycle/current cycle)))
+          (struct/set! source-code-cycle
+                       last-called
+                       (ts-now)
+                       buffer/source-code-cycle-state))
+      (progn
+        (funcall cycle-fn cycle)
+        (switch-to-buffer (cycle/current cycle))))))
+
+(defun buffer/cycle-next ()
+  "Cycle forward through the `buffer/source-code-buffers'."
+  (interactive)
+  (buffer/cycle #'cycle/next))
+
+(defun buffer/cycle-prev ()
+  "Cycle backward through the `buffer/source-code-buffers'."
+  (interactive)
+  (buffer/cycle #'cycle/prev))
+
+(defun buffer/ivy-source-code ()
+  "Use `ivy-read' to choose among all open source code buffers."
+  (interactive)
+  (ivy-read "Source code buffer: "
+            (-drop 1 (buffer/source-code-buffers))
+            :sort nil
+            :action #'switch-to-buffer))
+
+(defun buffer/show-previous ()
+  "Call `switch-to-buffer' on the previously visited buffer.
+This function ignores Emacs-generated buffers, i.e. the ones that look like
+  this: *Buffer*.  It also ignores buffers that are `dired-mode' or `erc-mode'.
+  This blacklist can easily be changed."
+  (interactive)
+  (let* ((xs (buffer/source-code-buffers))
+         (candidate (list/get 1 xs)))
+    (prelude/assert (maybe/some? candidate))
+    (switch-to-buffer candidate)))
+
+(when buffer/install-kbds?
+  (general-define-key
+   :states '(normal)
+   "C-f" #'buffer/cycle-next
+   "C-b" #'buffer/cycle-prev)
+  (general-define-key
+   :prefix "<SPC>"
+   :states '(normal)
+   "b" #'buffer/ivy-source-code
+   "<SPC>" #'buffer/show-previous
+   "k" #'kill-buffer))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when buffer/enable-tests?
+  (prelude/assert
+   (list/all? #'buffer/emacs-generated?
+              '("*scratch*"
+                "*Messages*"
+                "*shell*"
+                "*Shell Command Output*"
+                "*Occur*"
+                "*Warnings*"
+                "*Help*"
+                "*Completions*"
+                "*Apropos*"
+                "*info*"))))
+
+(provide 'buffer)
+;;; buffer.el ends here
diff --git a/emacs/.emacs.d/wpc/bytes.el b/emacs/.emacs.d/wpc/bytes.el
new file mode 100644
index 000000000000..d8bd2e288614
--- /dev/null
+++ b/emacs/.emacs.d/wpc/bytes.el
@@ -0,0 +1,109 @@
+;;; bytes.el --- Working with byte values -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Functions to help with human-readable representations of byte values.
+;;
+;; Usage:
+;; See the test cases for example usage.  Or better yet, I should use a type of
+;; structured documentation that would allow me to expose a view into the test
+;; suite here.  Is this currently possible in Elisp?
+;;
+;; API:
+;; - serialize :: Integer -> String
+;;
+;; Wish list:
+;; - Rounding: e.g. (bytes (* 1024 1.7)) => "2KB"
+
+;;; Code:
+
+;; TODO: Support -ibabyte variants like Gibibyte (GiB).
+
+;; Ranges:
+;;  B: [   0,  1e3)
+;; KB: [ 1e3,  1e6)
+;; MB: [ 1e6,  1e6)
+;; GB: [ 1e9, 1e12)
+;; TB: [1e12, 1e15)
+;; PB: [1e15, 1e18)
+;;
+;; Note: I'm currently not support exabytes because that causes the integer to
+;;  overflow.  I imagine a larger integer type may exist, but for now, I'll
+;;  treat this as a YAGNI.
+
+(require 'prelude)
+(require 'tuple)
+(require 'math)
+(require 'number)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst bytes/kb (math/exp 2 10)
+  "Number of bytes in a kilobyte.")
+
+(defconst bytes/mb (math/exp 2 20)
+  "Number of bytes in a megabytes.")
+
+(defconst bytes/gb (math/exp 2 30)
+  "Number of bytes in a gigabyte.")
+
+(defconst bytes/tb (math/exp 2 40)
+  "Number of bytes in a terabyte.")
+
+(defconst bytes/pb (math/exp 2 50)
+  "Number of bytes in a petabyte.")
+
+(defconst bytes/eb (math/exp 2 60)
+  "Number of bytes in an exabyte.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun bytes/classify (x)
+  "Return unit that closest fits byte count, X."
+  (prelude/assert (number/whole? x))
+  (cond
+   ((and (>= x 0)        (< x bytes/kb))     'byte)
+   ((and (>= x bytes/kb) (< x bytes/mb)) 'kilobyte)
+   ((and (>= x bytes/mb) (< x bytes/gb)) 'megabyte)
+   ((and (>= x bytes/gb) (< x bytes/tb)) 'gigabyte)
+   ((and (>= x bytes/tb) (< x bytes/pb)) 'terabyte)
+   ((and (>= x bytes/pb) (< x bytes/eb)) 'petabyte)))
+
+(defun bytes/to-string (x)
+  "Convert integer X into a human-readable string."
+  (let ((base-and-unit
+         (pcase (bytes/classify x)
+           ('byte     (tuple/from        1 "B"))
+           ('kilobyte (tuple/from bytes/kb "KB"))
+           ('megabyte (tuple/from bytes/mb "MB"))
+           ('gigabyte (tuple/from bytes/gb "GB"))
+           ('terabyte (tuple/from bytes/tb "TB"))
+           ('petabyte (tuple/from bytes/pb "PB")))))
+    (string/format "%d%s"
+                   (round x (tuple/first base-and-unit))
+                   (tuple/second base-and-unit))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(progn
+  (prelude/assert
+   (equal "1000B" (bytes/to-string 1000)))
+  (prelude/assert
+   (equal "2KB" (bytes/to-string (* 2 bytes/kb))))
+  (prelude/assert
+   (equal "17MB" (bytes/to-string (* 17 bytes/mb))))
+  (prelude/assert
+   (equal "419GB" (bytes/to-string (* 419 bytes/gb))))
+  (prelude/assert
+   (equal "999TB" (bytes/to-string (* 999 bytes/tb))))
+  (prelude/assert
+   (equal "2PB" (bytes/to-string (* 2 bytes/pb)))))
+
+(provide 'bytes)
+;;; bytes.el ends here
diff --git a/emacs/.emacs.d/wpc/cache.el b/emacs/.emacs.d/wpc/cache.el
new file mode 100644
index 000000000000..7b7e1aa2a37f
--- /dev/null
+++ b/emacs/.emacs.d/wpc/cache.el
@@ -0,0 +1,80 @@
+;;; cache.el --- Caching things -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; An immutable cache data structure.
+;;
+;; This is like a sideways stack, that you can pull values out from and re-push
+;; to the top.  It'd be like a stack supporting push, pop, pull.
+;;
+;; This isn't a key-value data-structure like you might expect from a
+;; traditional cache.  The name is subject to change, but the underlying idea of
+;; a cache remains the same.
+;;
+;; Think about prescient.el, which uses essentially an LRU cache integrated into
+;; counsel to help create a "clairovoyant", self-organizing list.
+;;
+;; Use-cases:
+;; - Keeps an cache of workspaces sorted as MRU with an LRU eviction strategy.
+
+;;; Code:
+
+(require 'prelude)
+(require 'struct)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defstruct cache xs)
+
+;; TODO: Prefer another KBD for yasnippet form completion than company-mode's
+;; current KBD.
+
+(defun cache/from-list (xs)
+  "Turn list, XS, into a cache."
+  (make-cache :xs xs))
+
+(defun cache/contains? (x xs)
+  "Return t if X in XS."
+  (->> xs
+       cache-xs
+       (list/contains? x)))
+
+(defun cache/touch (x xs)
+  "Ensure value X in cache, XS, is front of the list.
+If X isn't in XS (using `equal'), insert it at the front."
+  (struct/update
+   cache
+   xs
+   (>> (list/reject (lambda (y) (equal x y)))
+       (list/cons x))
+   xs))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(progn
+  (let ((cache (cache/from-list '("chicken" "nugget"))))
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; contains?/2
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    (prelude/refute
+     (cache/contains? "turkey" cache))
+    (prelude/assert
+     (cache/contains? "chicken" cache))
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; touch/2
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    (prelude/assert
+     (equal
+      (cache/touch "nugget" cache)
+      (cache/from-list '("nugget" "chicken"))))
+    (prelude/assert
+     (equal
+      (cache/touch "spicy" cache)
+      (cache/from-list '("spicy" "chicken" "nugget"))))))
+
+(provide 'cache)
+;;; cache.el ends here
diff --git a/emacs/.emacs.d/wpc/chrome.el b/emacs/.emacs.d/wpc/chrome.el
new file mode 100644
index 000000000000..133c7af355fa
--- /dev/null
+++ b/emacs/.emacs.d/wpc/chrome.el
@@ -0,0 +1,82 @@
+;;; chrome.el --- Helpers for Google Chrome -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Some helper functions for working with Google Chrome.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'macros)
+(require 'alist)
+(require 'list)
+(require 'general)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar chrome/install-kbds? t
+  "If t, install keybinding.")
+
+;; TODO: Consider modelling this as a rose-tree that can nest itself
+;; arbitrarily.
+;; TODO: Consider exporting existing chrome bookmarks.
+(defconst chrome/label->url
+  '(("Google" . "www.google.com")
+    ("Hacker News" . "news.ycombinator.com")
+    ("Gmail" . "www.gmail.com")
+    ("WhatsApp" . "web.whatsapp.com")
+    ("Google Chat" . "chat/")
+    ("Google Calendar" . "calendar/")
+    ("Teknql" . "teknql.slack.com/messages")
+    ("Twitter" . "twitter.com"))
+  "Mapping labels to urls for my bookmarks.")
+
+(defconst chrome/splash-pages
+  '("Google Calendar"
+    "Gmail"
+    "Google Chat"
+    "WhatsApp"
+    "Teknql")
+  "The pages that should open when I open Chrome.")
+
+;; TODO: Add defensive check to start chrome if it isn't already open.
+
+;; TODO: Support option to create new session even if one already exists.
+
+(defun chrome/open-splash-pages ()
+  "Opens Chrome with my preferred splash pages."
+  (interactive)
+  (->> chrome/splash-pages
+       (-map (lambda (x) (alist/get x chrome/label->url)))
+       chrome/open-urls))
+
+;; TODO: Support optional kwargs.
+(cl-defun chrome/open-url (url &key new-window?)
+  "Opens `URL' in google-chrome.
+Will open without toolbars if APP-MODE? is t."
+  (shell-command (s-concat
+                  "google-chrome "
+                  (if new-window? "--new-window " "")
+                  url)))
+
+(defun chrome/open-urls (urls)
+  "Open multiple `URLS' in chrome."
+  (chrome/open-url
+   (list/join " " urls)))
+
+(defun chrome/browse ()
+  "Display a counsel window for browsing URLs."
+  (interactive)
+  (ivy-read
+   "URL: "
+   chrome/label->url
+   :action (lambda (entry)
+             (chrome/open-url (cdr entry)))))
+
+(provide 'chrome)
+;;; chrome.el ends here
diff --git a/emacs/.emacs.d/wpc/clipboard.el b/emacs/.emacs.d/wpc/clipboard.el
new file mode 100644
index 000000000000..0688c9d87fe0
--- /dev/null
+++ b/emacs/.emacs.d/wpc/clipboard.el
@@ -0,0 +1,44 @@
+;;; clipboard.el --- Working with X11's pasteboard -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Simple functions for copying and pasting.
+;;
+;; Integrate with bburns/clipmon so that System Clipboard can integrate with
+;; Emacs's kill-ring.
+;;
+;; Wish list:
+;; - Create an Emacs integration with github.com/cdown/clipmenud.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'ivy-clipmenu)
+
+(prelude/assert (prelude/executable-exists? "clipmenu"))
+(prelude/assert (prelude/executable-exists? "clipmenud"))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defun clipboard/copy (x &key (message "[clipboard.el] Copied!"))
+  "Copy string, X, to X11's clipboard."
+  (kill-new x)
+  (message message))
+
+(cl-defun clipboard/paste (&key (message "[clipboard.el] Pasted!"))
+  "Paste contents of X11 clipboard."
+  (yank)
+  (message message))
+
+(defun clipboard/contents ()
+  "Return the contents of the clipboard as a string."
+  (substring-no-properties (current-kill 0)))
+
+(provide 'clipboard)
+;;; clipboard.el ends here
diff --git a/emacs/.emacs.d/wpc/colorscheme.el b/emacs/.emacs.d/wpc/colorscheme.el
new file mode 100644
index 000000000000..830fc5ac3e28
--- /dev/null
+++ b/emacs/.emacs.d/wpc/colorscheme.el
@@ -0,0 +1,96 @@
+;;; colorscheme.el --- Syntax highlight and friends -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;;
+;; TODO: Clarify this.
+;; Since I have my own definition of "theme", which couples wallpaper, font,
+;; with Emacs's traditional notion of the word "theme", I'm choosing to use
+;; "colorscheme" to refer to *just* the notion of syntax highlight etc.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'cycle)
+(require 'general)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defcustom colorscheme/install-kbds? t
+  "If non-nil, enable the keybindings.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defcustom colorscheme/whitelist
+  (cycle/from-list
+   (->> (custom-available-themes)
+        (list/map #'symbol-name)
+        (list/filter (>> (s-starts-with? "doom-")))
+        (list/map #'intern)))
+  "The whitelist of colorschemes through which to cycle.")
+
+(defun colorscheme/current ()
+  "Return the currently enabled colorscheme."
+  (cycle/current colorscheme/whitelist))
+
+(defun colorscheme/disable-all ()
+  "Disable all currently enabled colorschemes."
+  (interactive)
+  (->> custom-enabled-themes
+       (list/map #'disable-theme)))
+
+(defun colorscheme/set (theme)
+    "Call `load-theme' with `THEME', ensuring that the line numbers are bright.
+There is no hook that I'm aware of to handle this more elegantly."
+    (load-theme theme t)
+    (prelude/set-line-number-color "#da5468"))
+
+(defun colorscheme/whitelist-set (colorscheme)
+  "Focus the COLORSCHEME in the `colorscheme/whitelist' cycle."
+  (cycle/focus (lambda (x) (equal x colorscheme)) colorscheme/whitelist)
+  (colorscheme/set (colorscheme/current)))
+
+(defun colorscheme/ivy-select ()
+  "Load a colorscheme using ivy."
+  (interactive)
+  (let ((theme (ivy-read "Theme: " (cycle/to-list colorscheme/whitelist))))
+    (colorscheme/disable-all)
+    (colorscheme/set (intern theme))))
+
+(cl-defun colorscheme/cycle (&key forward?)
+  "Cycle next if `FORWARD?' is non-nil.
+Cycle prev otherwise."
+  (disable-theme (cycle/current colorscheme/whitelist))
+  (let ((theme (if forward?
+                   (cycle/next colorscheme/whitelist)
+                 (cycle/prev colorscheme/whitelist))))
+    (colorscheme/set theme)
+    (message (s-concat "Active theme: " (symbol/to-string theme)))))
+
+(defun colorscheme/next ()
+  "Disable the currently active theme and load the next theme."
+  (interactive)
+  (colorscheme/cycle :forward? t))
+
+(defun colorscheme/prev ()
+  "Disable the currently active theme and load the previous theme."
+  (interactive)
+  (colorscheme/cycle :forward? nil))
+
+;; Keybindings
+(when colorscheme/install-kbds?
+  (general-define-key
+   :prefix "<SPC>"
+   :states '(normal)
+   "Ft" #'colorscheme/next
+   "Pt" #'colorscheme/prev))
+
+(provide 'colorscheme)
+;;; colorscheme.el ends here
diff --git a/emacs/.emacs.d/wpc/constants.el b/emacs/.emacs.d/wpc/constants.el
new file mode 100644
index 000000000000..5bfedf5553c6
--- /dev/null
+++ b/emacs/.emacs.d/wpc/constants.el
@@ -0,0 +1,41 @@
+;;; constants.el --- Constants for organizing my Emacs -*- lexical-binding: t -*-
+;; Authpr: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; This file contains constants that are shared across my configuration.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'f)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Consider merging `ui.el' and `misc.el' because those are the only
+;; current consumers of these constants, and I'm unsure if the indirection that
+;; globally defined constants introduces is worth it.
+
+(defconst constants/current-project "~/universe"
+  "Variable holding the directory for my currently active project.")
+
+(prelude/assert (f-directory? constants/current-project))
+
+(defconst constants/mouse-kbds
+  '([mouse-1] [down-mouse-1] [drag-mouse-1] [double-mouse-1] [triple-mouse-1]
+    [mouse-2] [down-mouse-2] [drag-mouse-2] [double-mouse-2] [triple-mouse-2]
+    [mouse-3] [down-mouse-3] [drag-mouse-3] [double-mouse-3] [triple-mouse-3]
+    [mouse-4] [down-mouse-4] [drag-mouse-4] [double-mouse-4] [triple-mouse-4]
+    [mouse-5] [down-mouse-5] [drag-mouse-5] [double-mouse-5] [triple-mouse-5])
+  "All of the mouse-related keybindings that Emacs recognizes.")
+
+(defconst constants/fill-column 80
+  "Variable used to set the defaults for wrapping, highlighting, etc.")
+
+(provide 'constants)
+;;; constants.el ends here
diff --git a/emacs/.emacs.d/wpc/cycle.el b/emacs/.emacs.d/wpc/cycle.el
new file mode 100644
index 000000000000..9475ddd99659
--- /dev/null
+++ b/emacs/.emacs.d/wpc/cycle.el
@@ -0,0 +1,155 @@
+;;; cycle.el --- Simple module for working with cycles. -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Something like this may already exist, but I'm having trouble finding it, and
+;; I think writing my own is a nice exercise for learning more Elisp.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'math)
+(require 'maybe)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Wish list
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; - TODO: Provide immutable variant.
+;; - TODO: Replace mutable consumption with immutable variant.
+;; - TODO: Replace indexing with (math/mod current cycle).
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; `current-index' tracks the current index
+;; `xs' is the original list
+(cl-defstruct cycle current-index previous-index xs)
+
+(defconst cycle/enable-tests? t
+  "When t, run the tests defined herein.")
+
+(defun cycle/new (&rest xs)
+  "Create an empty cycle."
+  (make-cycle :current-index 0
+              :previous-index nil
+              :xs xs))
+
+(defun cycle/from-list (xs)
+  "Create a cycle from a list of `XS'."
+  (make-cycle :current-index 0
+              :previous-index nil
+              :xs xs))
+
+(defun cycle/to-list (xs)
+  "Return the list representation of a cycle, XS."
+  (cycle-xs xs))
+
+(defun next-index<- (lo hi x)
+  "Return the next index in a cycle when moving downwards.
+- `LO' is the lower bound.
+- `HI' is the upper bound.
+- `X' is the current index."
+  (if (< (- x 1) lo)
+      (- hi 1)
+    (- x 1)))
+
+(defun next-index-> (lo hi x)
+  "Return the next index in a cycle when moving upwards.
+- `LO' is the lower bound.
+- `HI' is the upper bound.
+- `X' is the current index."
+  (if (>= (+ 1 x) hi)
+      lo
+    (+ 1 x)))
+
+(defun cycle/previous-focus (cycle)
+  "Return the previously focused entry in CYCLE."
+  (let ((i (cycle-previous-index cycle)))
+    (if (maybe/some? i)
+        (nth i (cycle-xs cycle))
+      nil)))
+
+;; TODO: Consider adding "!" to the function name herein since many of them
+;; mutate the collection, and the APIs are beginning to confuse me.
+(defun cycle/focus-previous! (xs)
+  "Jump to the item in XS that was most recently focused; return the cycle.
+This will error when previous-index is nil.  This function mutates the
+underlying struct."
+  (let ((i (cycle-previous-index xs)))
+    (if (maybe/some? i)
+        (progn
+          (cycle/jump i xs)
+          (cycle/current xs))
+      (error "Cannot focus the previous element since cycle-previous-index is nil"))))
+
+(defun cycle/next (xs)
+  "Return the next value in `XS' and update `current-index'."
+  (let* ((current-index (cycle-current-index xs))
+         (next-index (next-index-> 0 (cycle/count xs) current-index)))
+    (struct/set! cycle previous-index current-index xs)
+    (struct/set! cycle current-index next-index xs)
+    (nth next-index (cycle-xs xs))))
+
+(defun cycle/prev (xs)
+  "Return the previous value in `XS' and update `current-index'."
+  (let* ((current-index (cycle-current-index xs))
+         (next-index (next-index<- 0 (cycle/count xs) current-index)))
+    (struct/set! cycle previous-index current-index xs)
+    (struct/set! cycle current-index next-index xs)
+    (nth next-index (cycle-xs xs))))
+
+(defun cycle/current (cycle)
+  "Return the current value in `CYCLE'."
+  (nth (cycle-current-index cycle) (cycle-xs cycle)))
+
+(defun cycle/count (cycle)
+  "Return the length of `xs' in `CYCLE'."
+  (length (cycle-xs cycle)))
+
+(defun cycle/jump (i xs)
+  "Jump to the I index of XS."
+  (let ((current-index (cycle-current-index xs))
+        (next-index (math/mod i (cycle/count xs))))
+    (struct/set! cycle previous-index current-index xs)
+    (struct/set! cycle current-index next-index xs))
+  xs)
+
+(defun cycle/focus (p cycle)
+  "Focus the element in CYCLE for which predicate, P, is t."
+  (let ((i (->> cycle
+                cycle-xs
+                (-find-index p))))
+    (if i
+        (cycle/jump i cycle)
+      (error "No element in cycle matches predicate"))))
+
+(defun cycle/contains? (x xs)
+  "Return t if cycle, XS, has member X."
+  (->> xs
+       cycle-xs
+       (list/contains? x)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when cycle/enable-tests?
+  (let ((xs (cycle/new 1 2 3)))
+    (prelude/assert (maybe/nil? (cycle/previous-focus xs)))
+    (prelude/assert (= 1 (cycle/current xs)))
+    (prelude/assert (= 2 (cycle/next xs)))
+    (prelude/assert (= 1 (cycle/previous-focus xs)))
+    (prelude/assert (= 1 (->> xs (cycle/jump 0) cycle/current)))
+    (prelude/assert (= 2 (->> xs (cycle/jump 1) cycle/current)))
+    (prelude/assert (= 3 (->> xs (cycle/jump 2) cycle/current)))
+    (prelude/assert (= 2 (cycle/previous-focus xs)))
+    (prelude/assert (= 2 (cycle/focus-previous! xs)))))
+
+(provide 'cycle)
+;;; cycle.el ends here
diff --git a/emacs/.emacs.d/wpc/device.el b/emacs/.emacs.d/wpc/device.el
new file mode 100644
index 000000000000..03eb55beb7f4
--- /dev/null
+++ b/emacs/.emacs.d/wpc/device.el
@@ -0,0 +1,38 @@
+;;; device.el --- Physical device information -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Functions for querying device information.
+
+;;; Code:
+
+(require 'dash)
+(require 'alist)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst device/hostname->device
+  '(("zeno.lon.corp.google.com" . work-desktop)
+    ("seneca" . work-laptop))
+  "Mapping hostname to a device symbol.")
+
+;; TODO: Should I generate these predicates?
+
+(defun device/classify ()
+  "Return the device symbol for the current host or nil if not supported."
+  (alist/get system-name device/hostname->device))
+
+(defun device/work-laptop? ()
+  "Return t if current device is work laptop."
+  (equal 'work-laptop
+         (device/classify)))
+
+(defun device/work-desktop? ()
+  "Return t if current device is work desktop."
+  (equal 'work-desktop
+         (device/classify)))
+
+(provide 'device)
+;;; device.el ends here
diff --git a/emacs/.emacs.d/wpc/display.el b/emacs/.emacs.d/wpc/display.el
new file mode 100644
index 000000000000..8e5b89030325
--- /dev/null
+++ b/emacs/.emacs.d/wpc/display.el
@@ -0,0 +1,98 @@
+;;; display.el --- Working with single or multiple displays -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Mostly wrappers around xrandr.
+;;
+;; TODO: Look into autorandr to see if it could be useful.
+;;
+;; Troubleshooting:
+;; The following commands help me when I (infrequently) interact with xrandr.
+;; - xrandr --listmonitors
+;; - xrandr --query
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst display/install-kbds? t
+  "When t, install the keybindings defined in this module.")
+
+;; TODO: Consider if this logic should be conditioned by `device/work-laptop?'.
+(defconst display/laptop-monitor "eDP1"
+  "The xrandr identifier for my primary screen (on work laptop).")
+
+;; TODO: Why is HDMI-1, eDP-1 sometimes and HDMI1, eDP1 other times.
+(defconst display/4k-monitor "HDMI1"
+  "The xrandr identifer for my 4K monitor.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Debug why something this scales to 4k appropriately and other times it
+;; doesn't.
+(defun display/enable-4k ()
+  "Attempt to connect to my 4K monitor."
+  (interactive)
+  (prelude/start-process
+   :name "display/enable-4k"
+   :command (string/format
+             "xrandr --output %s --above %s --primary --auto --dpi 144"
+             display/4k-monitor
+             display/laptop-monitor)))
+
+(defun display/disable-4k ()
+  "Disconnect from the 4K monitor."
+  (interactive)
+  (prelude/start-process
+   :name "display/disable-4k"
+   :command (string/format "xrandr --output %s --off"
+                           display/4k-monitor)))
+
+(defun display/enable-laptop ()
+  "Turn the laptop monitor off.
+Sometimes this is useful when I'm sharing my screen in a Google Hangout and I
+  only want to present one of my monitors."
+  (interactive)
+  (prelude/start-process
+   :name "display/disable-laptop"
+   :command (string/format "xrandr --output %s --auto"
+                           display/laptop-monitor)))
+
+(defun display/disable-laptop ()
+  "Turn the laptop monitor off.
+Sometimes this is useful when I'm sharing my screen in a Google Hangout and I
+  only want to present one of my monitors."
+  (interactive)
+  (prelude/start-process
+   :name "display/disable-laptop"
+   :command (string/format "xrandr --output %s --off"
+                           display/laptop-monitor)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Keybindings
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when display/install-kbds?
+  (general-define-key
+   :prefix "<SPC>"
+   :states '(normal)
+   "d0" #'display/disable-laptop
+   "d1" #'display/enable-laptop)
+  (general-define-key
+   :prefix "<SPC>"
+   :states '(normal)
+   "D0" #'display/disable-4k
+   "D1" #'display/enable-4k))
+
+(provide 'display)
+;;; display.el ends here
diff --git a/emacs/.emacs.d/wpc/do.el b/emacs/.emacs.d/wpc/do.el
new file mode 100644
index 000000000000..7dc2b260fdcd
--- /dev/null
+++ b/emacs/.emacs.d/wpc/do.el
@@ -0,0 +1,54 @@
+;;; do.el --- Small assertion library for Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Assertion library inspired by Elixir's core testing library.
+;;
+;; The goal here is to create this module without relying on other non-core
+;; Elisp libraries.  I will attempt to do this as long as I'm not sacrificing
+;; the readability of this code nor the ease at which it can be written.
+;;
+;; A note on testing:
+;; Another goal with this library is to blur the line between testing code and
+;; runtime code.  Developers should ideally be using `do/assert' and `do/refute'
+;; in their library code.  Because of this, I'm avoiding referring
+;; to the notion of testing in the names of these functions.
+;;
+;; Hypothesis:
+;; The lower the friction is for writing tests, the more likely people will
+;; write tests.
+
+;; TODO: Support better error messages, which might include information about
+;; line numbers in source code where the assertion failed.
+
+;; TODO: Consider offering the ability to have some of these functions compile
+;; to nothing at runtime if developers want to use them while developing without
+;; incurring the costs at runtime.
+
+;; TODO: Consider using this module instead of prelude.el.  Right now, I'm
+;; having troubling preferring one to the other.  The benefit of this module is
+;; that it's independent of prelude, but that might also be a downside, since
+;; the messaging that asserting should be a critical part of any core library
+;; like prelude.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defmacro do/assert (x)
+  "Errors unless X is t.
+These are strict assertions and purposely do not rely on truthiness."
+  (let ((as-string (format "%s" x)))
+    `(unless (equal t ,x)
+       (error (concat "Assertion failed: " ,as-string)))))
+
+(defmacro do/refute (x)
+  "Errors unless X is nil."
+  (let ((as-string (format "%s" x)))
+    `(unless (eq nil ,x)
+       (error (concat "Refutation failed: " ,as-string)))))
+
+(provide 'do)
+;;; do.el ends here
diff --git a/emacs/.emacs.d/wpc/dotfiles.el b/emacs/.emacs.d/wpc/dotfiles.el
new file mode 100644
index 000000000000..2e78cf213733
--- /dev/null
+++ b/emacs/.emacs.d/wpc/dotfiles.el
@@ -0,0 +1,53 @@
+;;; dotfiles.el --- Elisp to make dotfile management -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Quickly edit commonly used files.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'macros)
+(require 'f)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; API
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst dotfiles/install-kbds? t
+  "When t, install the keybindings.")
+
+(defconst dotfiles/whitelist
+  '(("compton" . "~/.config/compton.conf")
+    ("dotfiles" . "~/dotfiles/")
+    ("functions" . "~/functions.zsh")
+    ("aliases" . "~/aliases.zsh")
+    ("variables" . "~/variables.zsh")
+    ("Xresources" . "~/.Xresources.shared")
+    ("xsession" . "~/.xsessionrc.shared")
+    ("tmux" . "~/.tmux.conf")
+    ("zshrc" . "~/.zshrc")
+    ("config.fish" . "~/.config/fish/config.fish")
+    ("configuration.nix" . "~/Dropbox/programming/nixify/configuration.nix")
+    ("init.el" . "~/.emacs.d/init.el")
+    ("init.vim" . "~/.config/nvim/init.vim"))
+  "Dotfiles that I commonly edit.")
+
+(defun dotfiles/edit ()
+  "Select a dotfile from ivy and edit it in an Emacs buffer."
+  (interactive)
+  (ivy-read
+   "Dotfile: "
+   dotfiles/whitelist
+   :action (>> cdr find-file)))
+
+(defun dotfiles/find-emacs-file (name)
+  "Call `find-file' on NAME located in dotfiles's emacs.d directory."
+  (find-file
+   (f-join "~/dotfiles/configs/shared/.emacs.d" name)))
+
+(provide 'dotfiles)
+;;; dotfiles.el ends here
diff --git a/emacs/.emacs.d/wpc/dotted.el b/emacs/.emacs.d/wpc/dotted.el
new file mode 100644
index 000000000000..90ef39f92e7e
--- /dev/null
+++ b/emacs/.emacs.d/wpc/dotted.el
@@ -0,0 +1,49 @@
+;;; dotted.el --- Working with dotted pairs in Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Part of my primitives library extensions in Elisp.  Contrast my primitives
+;; with the wrapper extensions that I provide, which expose immutable variants
+;; of data structures like an list, alist, tuple, as well as quasi-typeclasses
+;; like sequence, etc.
+
+;;; Code:
+
+(require 'prelude)
+(require 'macros)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defun dotted/new (&optional a b)
+  "Create a new dotted pair (i.e. cons cell)."
+  (cons a b))
+
+(defun dotted/instance? (x)
+  "Return t if X is a dotted pair."
+  (let ((b (cdr x)))
+    (and b (atom b))))
+
+(defun dotted/first (x)
+  "Return the first element of X."
+  (car x))
+
+(defun dotted/second (x)
+  "Return the second element of X."
+  (cdr x))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(progn
+  (prelude/assert
+   (equal '(fname . "Bob") (dotted/new 'fname "Bob")))
+  (prelude/assert
+   (dotted/instance? '(one . two)))
+  (prelude/refute
+   (dotted/instance? '(1 2 3))))
+
+(provide 'dotted)
+;;; dotted.el ends here
diff --git a/emacs/.emacs.d/wpc/email.el b/emacs/.emacs.d/wpc/email.el
new file mode 100644
index 000000000000..6a266a717cd2
--- /dev/null
+++ b/emacs/.emacs.d/wpc/email.el
@@ -0,0 +1,11 @@
+;;; email.el --- My Emacs email settings -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Attempting to configure to `notmuch' for my personal use.
+
+;;; Code:
+(message "Not implemented.")
+
+(provide 'email)
+;;; email.el ends here
diff --git a/emacs/.emacs.d/wpc/entr.el b/emacs/.emacs.d/wpc/entr.el
new file mode 100644
index 000000000000..ac2a5812c328
--- /dev/null
+++ b/emacs/.emacs.d/wpc/entr.el
@@ -0,0 +1,115 @@
+;;; entr.el --- Working with terminals and entr -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Help make watch commands easier.
+;;
+;; This should be entirely temporary because in reality we should be able to use
+;; Emacs's buffer watching abilities to run commands.
+;; TODO: Explore Emacs integration that obviates `entr`.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'f)
+(require 'buffer)
+(require 'prelude)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Support a generic file-watcher for commonly used languages.
+(defconst entr/major-mode->save-handler
+  '((python-mode . entr/handle-python3))
+  "Mapping of language to the `after-save-hook' function it should register.")
+
+(defun entr/shell-command-to-buffer (cmd name)
+  "Run CMD in a shell and output to the buffer NAME.
+The buffer is a find-or-create operation.
+The buffer is erased between runs with `erase-buffer'."
+  (let ((b (buffer/find-or-create name)))
+    (with-current-buffer b (erase-buffer))
+    (shell-command cmd b)
+    (buffer/show b)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Python
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: This should be a top-level function.
+(defconst entr/handle-python3
+  (lambda ()
+    (entr/shell-command-to-buffer
+     (format "python3 %s" (buffer-file-name))
+     "*python3*"))
+  "Function that is registered as the `after-save-hook' for python3.")
+
+(defun entr/register-python3 ()
+  "Register a buffer-local `after-save-hook' for calling python3 with filename."
+  (interactive)
+  (add-hook 'after-save-hook entr/handle-python3 nil t))
+
+(defun entr/deregister-python3 ()
+  "Remove the buffer-local `after-save-hook' for python3."
+  (interactive)
+  (remove-hook 'after-save-hook entr/handle-python3 t))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Protobuf
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun entr/format-protobuf ()
+  "Formats a protobuf buffer."
+  (call-interactively #'clang-format))
+
+;; TODO: Run this automatically with .proto file extensions.  Do this after
+;; verifying that `clang-format' complies with Google's style guide.
+(defun entr/register-protobuf ()
+  "Register a buffer-local `before-save-hook' for formatting protobuf buffers."
+  (interactive)
+  (add-hook
+   'before-save-hook
+   #'entr/format-protobuf
+   nil
+   t))
+
+;; TODO: Is there an interactive way to remove hooks in Emacs?
+(defun entr/deregister-protobuf ()
+  "Remove the buffer-local `before-save-hook' for protobuf."
+  (interactive)
+  (remove-hook
+   'before-save-hook
+   #'entr/format-protobuf
+   t))
+
+;; TODO: Support this.  Currently the `intern' call is the problem.
+;; (defun entr/ivy-remove-hook (hook)
+;;   "Use Counsel to remove a handler from HOOK."
+;;   (interactive)
+;;   (ivy-read
+;;    "Remove hook: "
+;;    (intern (prelude/prompt "Hook name: "))
+;;    :action (lambda (x) (message x))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Miscellaneous
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun entr/command (command)
+  "Create a terminal instance with entr running COMMAND.
+COMMAND is a function that is called with the current filename."
+  ;; Algorithm:
+  ;; - Get buffer's filename.
+  ;; - Open terminator running: `echo entr <filename> | entr <command>`.
+  (interactive)
+  (with-current-buffer (current-buffer)
+      (let ((filename (buffer-file-name)))
+        (prelude/inspect
+         (format "echo %s | entr %s" filename (funcall command filename))))))
+
+(provide 'entr)
+;;; entr.el ends here
diff --git a/emacs/.emacs.d/wpc/enum.el b/emacs/.emacs.d/wpc/enum.el
new file mode 100644
index 000000000000..078e7972099c
--- /dev/null
+++ b/emacs/.emacs.d/wpc/enum.el
@@ -0,0 +1,98 @@
+;;; enum.el --- Enumerable protocol for Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Heavily influenced by Elixir.
+
+;; I will not be implement every function in the Enum library, since I don't
+;; need every function.  Some of the streaming functionality may prove difficult
+;; to write in Elisp.  We shall see.
+
+;; TODO: Implement the following functions:
+;; - all?/2
+;; - any?/2
+;; - at/3
+;; - chunk_by/2
+;; - chunk_every/{2,3,4}
+;; - chunk_while/4
+;; - concat/1
+;; - concat/2
+;; - count/{1,2}
+;; - dedup/1 # prefer calling this function dedupe
+;; - dedup_by/2 # same as above
+;; - drop/2
+;; - drop_every/2
+;; - drop_while/2
+;; - each/2
+;; - empty?/1
+;; - fetch/2
+;; - fetch!/2
+;; - filter/2
+;; - find/3
+;; - find_index/2
+;; - find_value/3
+;; - flat_map/2
+;; - flat_map_reduce/3
+;; - group_by/3
+;; - intersperse/2
+;; - into/{2,3}
+;; - join/2
+;; - map/2
+;; - map_every/3
+;; - map_join/3
+;; - map_reduce/3
+;; - max/2
+;; - max_by/3
+;; - member?/2 # consider calling this contains?
+;; - min/2
+;; - min_by/2
+;; - min_max/2 # This is a great function because of O(n) time.
+;; - min_max_by/3
+;; - random/1 # Consider just sample with num=1
+;; - reduce/{2,3}
+;; - reduce_while/3
+;; - reject/2
+;; - reverse/{1,2}
+;; - reverse_slice/3
+;; - scan/{2,3}
+;; - shuffle/1
+;; - slice/{2,3}
+;; - sort/{1,2}
+;; - sort/2
+;; - sort_by/3
+;; - split/2
+;; - split_while/2
+;; - split_with/2
+;; - sum/1
+;; - take/2
+;; - take_every/2
+;; - take_random/2 # prefer calling this function sample
+;; - take_while/2
+;; - to_list/1
+;; - uniq/1 # prefer calling this unique
+;; - uniq_by/2 # prefer calling this unique-by
+;; - unzip/1
+;; - with_index/2
+;; - zip/{1,2}
+
+;; TODO: Consider how to handle dispatching by type.
+
+;; TODO: Which types should be supported herein?
+;; - linked-lists
+;; - associative-lists
+;; - cycles
+
+;; Warning: This module is a total work-in-progress, and it's quite possible
+;; that I may never even finish it.
+
+;;; Code:
+
+(defun enum/count (xs)
+  "Return the number of elements in `XS'."
+  (cond
+   ((alist/instance? xs) (alist/count xs))
+   ((list/instance?  xs) (list/length xs)))
+  )
+
+(provide 'enum)
+;;; enum.el ends here
diff --git a/emacs/.emacs.d/wpc/finance.el b/emacs/.emacs.d/wpc/finance.el
new file mode 100644
index 000000000000..b124061ccba3
--- /dev/null
+++ b/emacs/.emacs.d/wpc/finance.el
@@ -0,0 +1,119 @@
+;;; finance.el --- Functions to help me organize my finances -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Using functions to organize my financial thinking.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'math)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar finance/enable-tests? t
+  "When t, run the tests defined herein.")
+
+;; TODO: Support printing an org-table of these amount in a similar format to:
+;; https://keisan.casio.com/exec/system/1234231998
+(cl-defun finance/future-value (amt
+                                &key
+                                num-years
+                                (frequency 'monthly)
+                                (interest-rate 0.06)
+                                (payment-due-at 'beg)
+                                (present-value 0))
+  "Compute the Future Value of AMT.
+
+This function assumes that the interest rate is applied annually and not
+monthly.
+
+This function will attempt to provide the following defaults:
+- frequency: 'monthly
+- interest-rate: 6%
+- payment-due-at: 'beg
+- present-value: 0.00"
+  (prelude/assert (set/contains? payment-due-at (set/new 'beg 'end)))
+  (prelude/assert (set/contains? frequency (set/new 'annually
+                                                    'semiannually
+                                                    'quarterly
+                                                    'monthly)))
+  (let ((pmt amt)
+        (k (alist/get frequency '((annually . 1)
+                                  (semiannually . 2)
+                                  (quarterly . 4)
+                                  (monthly . 12))))
+        (r interest-rate)
+        (n num-years)
+        (pv present-value))
+    (if (= 0 r)
+        (+ pv (* pmt n k))
+      (if (equal 'beg payment-due-at)
+          (+ (* pv (math/exp (+ 1 (/ r k)) (* n k)))
+             (* pmt
+                (/ (- (math/exp (+ 1 (/ r k)) (* n k)) 1)
+                   (/ r k))
+                (+ 1 (/ r k))))
+        (+ (* pv (math/exp (+ 1 (/ r k)) (* n k)))
+           (* pmt
+              (/ (- (math/exp (+ 1 (/ r k)) (* n k)) 1)
+                 (/ r k))))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when finance/enable-tests?
+  (prelude/assert
+   (equal "1551.27"
+          (string/format "%0.2f"
+                         (finance/future-value
+                          9.99
+                          :interest-rate 0.05
+                          :num-years 10
+                          :frequency 'monthly
+                          :payment-due-at 'end
+                          :present-value 0))))
+  (prelude/assert
+   (equal "14318.34"
+          (string/format "%0.2f"
+                         (finance/future-value 10.0 :num-years 35))))
+  (prelude/assert
+   (equal "4200.00"
+          (string/format "%0.2f"
+                         (finance/future-value
+                          10.0
+                          :interest-rate 0.0
+                          :num-years 35
+                          :frequency 'monthly
+                          :payment-due-at 'beg
+                          :present-value 0))))
+  (prelude/assert
+   (equal "14318.34"
+          (string/format "%0.2f"
+                         (finance/future-value
+                          10.0
+                          :interest-rate 0.06
+                          :num-years 35
+                          :frequency 'monthly
+                          :payment-due-at 'beg
+                          :present-value 0))))
+  (prelude/assert
+   (equal "38282.77"
+          (string/format "%0.2f"
+                         (finance/future-value
+                          10.0
+                          :interest-rate 0.1
+                          :num-years 35
+                          :frequency 'monthly
+                          :payment-due-at 'beg
+                          :present-value 0)))))
+
+(provide 'finance)
+;;; finance.el ends here
diff --git a/emacs/.emacs.d/wpc/fonts.el b/emacs/.emacs.d/wpc/fonts.el
new file mode 100644
index 000000000000..3c6fe6bfebfb
--- /dev/null
+++ b/emacs/.emacs.d/wpc/fonts.el
@@ -0,0 +1,153 @@
+;;; fonts.el --- Font preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Control my font preferences with ELisp.
+
+;;; Code:
+
+;; TODO: `defcustom' font-size.
+;; TODO: `defcustom' fonts.
+;; TODO: Remove wpc/ namespace.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'cycle)
+(require 'device)
+(require 'maybe)
+(require 'general)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Troubleshoot why "8" appears so large on my desktop.
+
+;; TODO: Consider having a different font size when I'm using my 4K monitor.
+
+(defconst fonts/size
+  (pcase (device/classify)
+    ('work-laptop  "9")
+    ('work-desktop "8"))
+  "My preferred default font-size, which is device specific.")
+
+(defconst fonts/keybindings? t
+  "Install the keybindings when non-nil.")
+
+(defconst fonts/size-step 10
+  "The amount (%) by which to increase or decrease a font.")
+
+(defconst fonts/hacker-news-recommendations
+  '("APL385 Unicode"
+    "Go Mono"
+    "Sudo"
+    "Monoid"
+    "Input Mono Medium" ;; NOTE: Also "Input Mono Thin" is nice.
+    )
+  "List of fonts optimized for programming I found in a HN article.")
+
+(defconst fonts/whitelist
+  (cycle/from-list
+   (list/concat
+    fonts/hacker-news-recommendations
+    '("JetBrainsMono"
+      "Mononoki Medium"
+      "Monospace"
+      "Operator Mono Light"
+      "Courier"
+      "Andale Mono"
+      "Source Code Pro"
+      "Terminus")))
+  "This is a list of my preferred fonts.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: fonts and fonts/whitelist make it difficult to name functions like
+;; fonts/set as a generic Emacs function vs choosing a font from the whitelist.
+
+(cl-defun fonts/cycle (&key forward?)
+  "Cycle forwards when `FORWARD?' non-nil."
+  (let ((font (if forward?
+                  (cycle/next fonts/whitelist)
+                (cycle/prev fonts/whitelist))))
+    (message (s-concat "Active font: " font))
+    (fonts/set font)))
+
+(defun fonts/next ()
+  "Quickly cycle through preferred fonts."
+  (interactive)
+  (fonts/cycle :forward? t))
+
+(defun fonts/prev ()
+  "Quickly cycle through preferred fonts."
+  (interactive)
+  (fonts/cycle :forward? nil))
+
+(defun fonts/set (font &optional size)
+  "Change the font to `FONT' with option integer, SIZE, in pixels."
+  (if (maybe/some? size)
+      (set-frame-font (string/format "%s %s" font size) nil t)
+    (set-frame-font font nil t)))
+
+(defun fonts/whitelist-set (font)
+  "Focuses the FONT in the `fonts/whitelist' cycle.
+The size of the font is determined by `fonts/size'."
+  (prelude/assert (cycle/contains? font fonts/whitelist))
+  (cycle/focus (lambda (x) (equal x font)) fonts/whitelist)
+  (fonts/set (fonts/current) fonts/size))
+
+(defun fonts/ivy-select ()
+  "Select a font from an ivy prompt."
+  (interactive)
+  (fonts/whitelist-set
+   (ivy-read "Font: " (cycle/to-list fonts/whitelist))))
+
+(defun fonts/print-current ()
+  "Message the currently enabled font."
+  (interactive)
+  (message
+   (string/format "[fonts] Current font: \"%s\""
+                  (fonts/current))))
+
+(defun fonts/current ()
+  "Return the currently enabled font."
+  (cycle/current fonts/whitelist))
+
+(defun fonts/increase-size ()
+  "Increase font size."
+  (interactive)
+  (->> (face-attribute 'default :height)
+       (+ fonts/size-step)
+       (set-face-attribute 'default (selected-frame) :height)))
+
+(defun fonts/decrease-size ()
+  "Decrease font size."
+  (interactive)
+  (->> (face-attribute 'default :height)
+       (+ (- fonts/size-step))
+       (set-face-attribute 'default (selected-frame) :height)))
+
+(defun fonts/reset-size ()
+  "Restore font size to its default value."
+  (interactive)
+  (fonts/whitelist-set (fonts/current)))
+
+(when fonts/keybindings?
+  (progn
+    (general-define-key
+     :prefix "<SPC>"
+     :states '(normal)
+     "Ff" #'fonts/next
+     "Pf" #'fonts/prev)
+    (general-define-key "s-9" #'fonts/ivy-select)
+    (general-define-key "s-0" #'fonts/reset-size)
+    (general-define-key "s-j" #'fonts/decrease-size)
+    (general-define-key "s-k" #'fonts/increase-size)))
+
+(provide 'fonts)
+;;; fonts.el ends here
diff --git a/emacs/.emacs.d/wpc/fs.el b/emacs/.emacs.d/wpc/fs.el
new file mode 100644
index 000000000000..b1a79e280a57
--- /dev/null
+++ b/emacs/.emacs.d/wpc/fs.el
@@ -0,0 +1,65 @@
+;;; fs.el --- Make working with the filesystem easier -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Ergonomic alternatives for working with the filesystem.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'f)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun fs/ensure-file (path)
+  "Ensure that a file and its directories in `PATH' exist.
+Will error for inputs with a trailing slash."
+  (when (s-ends-with? "/" path)
+    (error (format "Input path has trailing slash: %s" path)))
+  (->> path
+       f-dirname
+       fs/ensure-dir)
+  (f-touch path))
+
+(f-dirname "/tmp/a/b/file.txt")
+
+(defun fs/ensure-dir (path)
+  "Ensure that a directory and its ancestor directories in `PATH' exist."
+  (->> path
+       f-split
+       (apply #'f-mkdir)))
+
+(defun fs/ls (dir &optional full-path?)
+  "List the files in `DIR' one-level deep.
+Should behave similarly in spirit to the Unix command, ls.
+If `FULL-PATH?' is set, return the full-path of the files."
+  (-drop 2 (directory-files dir full-path?)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Support `refute' function / macro.
+(ert-deftest fs/test/ensure-file ()
+  (let ((file "/tmp/file/a/b/c/file.txt"))
+    ;; Ensure this file doesn't exist first to prevent false-positives.
+    (f-delete file t)
+    (fs/ensure-file file)
+    (should (and (f-exists? file)
+                 (f-file? file)))))
+
+(ert-deftest fs/test/ensure-dir ()
+  (let ((dir "/tmp/dir/a/b/c"))
+    ;; Ensure the directory doesn't exist.
+    (f-delete dir t)
+    (fs/ensure-dir dir)
+    (should (and (f-exists? dir)
+                 (f-dir? dir)))))
+
+(provide 'fs)
+;;; fs.el ends here
diff --git a/emacs/.emacs.d/wpc/functions.el b/emacs/.emacs.d/wpc/functions.el
new file mode 100644
index 000000000000..2ef82d54bbe1
--- /dev/null
+++ b/emacs/.emacs.d/wpc/functions.el
@@ -0,0 +1,133 @@
+;; functions.el --- Helper functions for my Emacs development -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; This file hopefully contains friendly APIs that making ELisp development more
+;; enjoyable.
+
+;; TODO: Break these out into separate modules.
+
+;;; Code:
+(defun wpc/evil-window-vsplit-right ()
+  (interactive)
+  (evil-window-vsplit)
+  (windmove-right))
+
+(defun wpc/evil-window-split-down ()
+  (interactive)
+  (evil-window-split)
+  (windmove-down))
+
+(defun wpc/reindent-defun-and-align-clojure-map ()
+  (interactive)
+  (call-interactively #'paredit-reindent-defun)
+  (call-interactively #'clojure-align))
+
+(defun wpc/find-file ()
+  "Prefer project-based file-finding if inside of project; otherwise gracefully fallback."
+  (interactive)
+  (with-current-buffer (current-buffer)
+    (if (projectile-project-p)
+        (call-interactively #'counsel-projectile-find-file)
+      (call-interactively #'find-file))))
+
+(defun wpc/find-file-split (filename)
+  "Creates a window split and then edits `filename'."
+  (interactive)
+  (evil-window-vsplit)
+  (find-file filename))
+
+(defun wpc/find-or-create-js-test ()
+  (->> buffer-file-name
+       (s-chop-suffix ".js")
+       (s-append ".test.js")
+       (find-file)))
+
+(defun wpc/find-or-create-js-module ()
+  (->> buffer-file-name
+       (s-chop-suffix ".test.js")
+       (s-append ".js")
+       (find-file)))
+
+(defun wpc/find-or-create-js-store ()
+  (->> buffer-file-name
+       (s-replace "index.js" "store.js")
+       (find-file)))
+
+(defun wpc/find-or-create-js-component ()
+  (->> buffer-file-name
+       (s-replace "store.js" "index.js")
+       (find-file)))
+
+(defun wpc/toggle-between-js-test-and-module ()
+  "Toggle between a Javascript test or module."
+  (interactive)
+  (if (s-ends-with? ".test.js" buffer-file-name)
+      (wpc/find-or-create-js-module)
+    (if (s-ends-with? ".js" buffer-file-name)
+        (wpc/find-or-create-js-test)
+      (message "Not in a Javascript file. Exiting..."))))
+
+(defun wpc/toggle-between-js-component-and-store ()
+  "Toggle between a React component and its Redux store."
+  (interactive)
+  (if (s-ends-with? "index.js" buffer-file-name)
+      (wpc/find-or-create-js-store)
+    (if (or (s-ends-with? "store.js" buffer-file-name)
+            (s-ends-with? "store.test.js" buffer-file-name))
+        (wpc/find-or-create-js-component)
+      (message "Not in a React/Redux file. Exiting..."))))
+
+(defun wpc/read-file-as-string (filename)
+  (with-temp-buffer
+    (insert-file-contents filename)
+    (s-trim (buffer-string))))
+
+(defun wpc/create-snippet ()
+  "Creates a window split and then opens the Yasnippet editor."
+  (interactive)
+  (evil-window-vsplit)
+  (call-interactively #'yas-new-snippet))
+
+(defun wpc/jump-to-parent-file ()
+  "Jumps to a React store or component's parent file. Useful for store or index file."
+  (interactive)
+  (-> buffer-file-name
+      f-dirname
+      (f-join "..")
+      (f-join (f-filename buffer-file-name))
+      find-file))
+
+(defun wpc/add-earmuffs (x)
+  "Returns X surrounded by asterisks."
+  (format "*%s*" x))
+
+(defun wpc/put-file-name-on-clipboard ()
+  "Put the current file name on the clipboard"
+  (interactive)
+  (let ((filename (if (equal major-mode 'dired-mode)
+                      default-directory
+                    (buffer-file-name))))
+    (when filename
+      (with-temp-buffer
+        (insert filename)
+        (clipboard-kill-region (point-min) (point-max)))
+      (message filename))))
+
+(s-replace "/" "x" "a/b/c")
+
+(defun wpc/evil-replace-under-point ()
+  "Faster than typing %s//thing/g."
+  (interactive)
+  (let ((term (s-replace "/" "\\/" (symbol/to-string (symbol-at-point)))))
+    (save-excursion
+      (evil-ex (concat "%s/\\b" term "\\b/")))))
+
+(defun buffer-dirname ()
+  "Return the directory name of the current buffer as a string."
+  (->> buffer-file-name
+       f-dirname
+       f-filename))
+
+(provide 'functions)
+;;; functions.el ends here
diff --git a/emacs/.emacs.d/wpc/graph.el b/emacs/.emacs.d/wpc/graph.el
new file mode 100644
index 000000000000..c68c308590f4
--- /dev/null
+++ b/emacs/.emacs.d/wpc/graph.el
@@ -0,0 +1,91 @@
+;;; graph.el --- Working with in-memory graphs -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;;
+;; Remember that there are optimal three ways to model a graph:
+;; 1. Edge List
+;; 2. Vertex Table (a.k.a. Neighbors Table)
+;; 3. Adjacency Matrix
+;;
+;; I may call these "Edges", "Neighbors", "Adjacencies" to avoid verbose naming.
+;; For now, I'm avoiding dealing with Adjacency Matrices as I don't have an
+;; immediate use-case for them.  This is subject to change.
+;;
+;; There are also hybrid representations of graphs that combine the three
+;; aforementioned models.  I believe Erlang's digraph module models graphs in
+;; Erlang Term Storage (i.e. ETS) this way.
+;; TODO: Verify this claim.
+;;
+;; Graphs can be weighted or unweighted.  They can also be directed or
+;; undirected.
+;; TODO: Create a table explaining all graph variants.
+;;
+;; TODO: Figure out the relationship of this module and tree.el, which should in
+;; principle overlap.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; For now, I'll support storing *either* neighbors or edges in the graph struct
+;; as long as both aren't set, since that introduces consistency issues.  I may
+;; want to handle that use-case in the future, but not now.
+(cl-defstruct graph neighbors edges)
+
+;; TODO: How do you find the starting point for a topo sort?
+(defun graph/sort (xs)
+  "Return a topological sort of XS.")
+
+(defun graph/from-edges (xs)
+  "Create a graph struct from the Edge List, XS.
+The user must pass in a valid Edge List since asserting on the shape of XS might
+  be expensive."
+  (make-graph :edges xs))
+
+(defun graph/from-neighbors (xs)
+  "Create a graph struct from a Neighbors Table, XS.
+The user must pass in a valid Neighbors Table since asserting on the shape of
+  XS might be expensive."
+  (make-graph :neighbors xs))
+
+(defun graph/instance? (xs)
+  "Return t if XS is a graph struct."
+  (graph-p xs))
+
+;; TODO: Model each of the mapping functions into an isomorphism.
+(defun graph/edges->neighbors (xs)
+  "Map Edge List, XS, into a Neighbors Table."
+  (prelude/assert (graph/instance? xs)))
+
+(defun graph/neighbors->edges (xs)
+  "Map Neighbors Table, XS, into an Edge List."
+  (prelude/assert (graph/instance? xs)))
+
+;; Below are three different models of the same unweighted, directed graph.
+
+(defvar graph/edges
+  '((a . b) (a . c) (a . e)
+    (b . c) (b . d)
+    (c . e)
+    (d . f)
+    (e . d) (e . f)))
+
+(defvar graph/neighbors
+  ((a b c e)
+   (b c d)
+   (c e)
+   (d f)
+   (e d g)
+   (f)))
+
+(provide 'graph)
+;;; graph.el ends here
diff --git a/emacs/.emacs.d/wpc/imdb.el b/emacs/.emacs.d/wpc/imdb.el
new file mode 100644
index 000000000000..2969da140935
--- /dev/null
+++ b/emacs/.emacs.d/wpc/imdb.el
@@ -0,0 +1,128 @@
+;;; imdb.el --- Internet Movie Database -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Some Elisp to help me pick movies more quickly.
+
+;;; Code:
+
+(require 'f)
+(require 'macros)
+(require 'pcre2el)
+(require 'random)
+(require 'maybe)
+
+;; TODO: How do you support types herein?
+(cl-defstruct movie
+  name
+  year
+  director
+  watched?)
+
+;; TODO: Support famous directors like:
+;; - Wes Anderson
+;; - Woody Allen
+;; - Tarantino
+;; - Coen Brothers
+;; - Alfonso Cauron
+;; - Alejandro González Iñárritu
+;; - Alfred Hitchcock
+;; - Stanley Kubrick
+
+;; TODO: Dump this into SQL.
+
+(defconst imdb/kubrick-films
+  (->> '((:watched? nil :year 1951 :name "Flying Padre")
+         (:watched? nil :year 1953 :name "Fear and Desire")
+         (:watched? nil :year 1953 :name "The Seafarers")
+         (:watched? nil :year 1955 :name "Killer's Kiss")
+         (:watched? nil :year 1956 :name "The Killing")
+         (:watched? nil :year 1957 :name "Paths of Glory")
+         (:watched? nil :year 1960 :name "Spartacus")
+         (:watched? nil :year 1962 :name "Lolita")
+         (:watched? nil :year 1964 :name "Dr. Strangelove")
+         (:watched? nil :year 1968 :name "2001: A Space Odyssey")
+         (:watched? t   :year 1971 :name "A Clockwork Orange")
+         (:watched? nil :year 1975 :name "Barry Lyndon")
+         (:watched? nil :year 1980 :name "The Shining")
+         (:watched? t   :year 1987 :name "Full Metal Jacket")
+         (:watched? nil :year 1999 :name "Eyes Wide Shut"))
+       (list/map (lambda (x)
+                   (make-movie :name (plist-get :name x)
+                               :year (plist-get :year x)
+                               :director "Stanley Kubrick"
+                               :watched? (plist-get :watched? x))))))
+
+(defconst imdb/non-top-250
+  (->> '("Doctor Zhivago"
+         )
+       (list/map #'imdb/new-movie)))
+
+(defun imdb/new-movie (name)
+  "Create a new movie with NAME."
+  (make-movie :name name
+              :year nil
+              :director nil
+              :watched? nil))
+
+(defun imdb/org->movie (line)
+  "Parse an org LINE into a movie struct."
+  (let ((match (s-match
+                (pcre-to-elisp "^\*\*\s(TODO|DONE)\s(.+)$")
+                line)))
+    (if (maybe/some? match)
+        (make-movie :name (list/get 2 match)
+                    :year nil
+                    :director nil
+                    :watched? (equal "DONE" (list/get 1 match)))
+      (error (s-concat "Parsing error: " line)))))
+
+;; TODO: Store these in a database or define them herein.
+(defun imdb/org->movies ()
+  "Parse entire IMDB org file into movie structs."
+  (->> "~/Dropbox/org/imdb_top_250.org"
+       f-read
+       (s-split "\n")
+       (-drop 1)
+       (list/filter (>> (s-starts-with? "** ")))
+       (list/map #'imdb/org->movie)))
+
+(defun imdb/watched? (movie)
+  "Return t if MOVIE has been watched."
+  (movie-watched? movie))
+
+(defconst imdb/movies (imdb/org->movies)
+  "Structs of all watched movies.")
+
+(defun imdb/unwatched ()
+  "Return list of unwatched movies."
+  (->> imdb/movies
+       (list/filter (lambda (x) (not (imdb/watched? x))))))
+
+(defun imdb/name (movie)
+  "Return name of MOVIE."
+  (movie-name movie))
+
+
+(defun imdb/suggest ()
+  "Randomly select movie from unwatched list."
+  (->> (imdb/unwatched)
+       (random/choice)
+       (imdb/name)))
+
+(defun imdb/unwatched-list ()
+  "Dump all unwatched movies into a list."
+  (f-write-text (->> (imdb/unwatched)
+                     (list/map #'imdb/name)
+                     (s-join "\n"))
+                'utf-8
+                "/tmp/unwatched.txt"))
+
+(macros/comment
+ (imdb/org->movies)
+ (imdb/unwatched-list)
+ (imdb/suggest)
+ )
+
+(provide 'imdb)
+;;; imdb.el ends here
diff --git a/emacs/.emacs.d/wpc/irc.el b/emacs/.emacs.d/wpc/irc.el
new file mode 100644
index 000000000000..b9a1e3131769
--- /dev/null
+++ b/emacs/.emacs.d/wpc/irc.el
@@ -0,0 +1,177 @@
+;;; irc.el --- Configuration for IRC chat -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Need to decide which client I will use for IRC.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'erc)
+(require 'cycle)
+(require 'string)
+(require 'prelude)
+(require 'alist)
+(require 'set)
+(require 'maybe)
+(require 'macros)
+(require 'password-store)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst irc/enable-tests? t
+  "When t, run the tests defined herein.")
+
+(setq erc-rename-buffers t)
+
+;; TODO: Find a way to avoid putting "freenode" and "#freenode" as channels
+;; here.  I'm doing it because when erc first connects, it's `(buffer-name)' is
+;; "freenode", so when `irc/next-channel' is called, it 404s on the
+;; `cycle/contains?' call in `irc/channel->cycle" unless "freenode" is there. To
+;; make matters even uglier, when `erc-join-channel' is called with "freenode"
+;; as the value, it connects to the "#freenode" channel, so unless "#freenode"
+;; exists in this cycle also, `irc/next-channel' breaks again.  This doesn't
+;; pass my smell test.
+(defconst irc/server->channels
+  `(("irc.freenode.net"    . ,(cycle/new "freenode" "#freenode" "#nixos" "#emacs" "#pass"))
+    ("irc.corp.google.com" . ,(cycle/new "#omg" "#london" "#panic" "#prod-team")))
+  "Mapping of IRC servers to a cycle of my preferred channels.")
+
+;; TODO: Assert that no two servers have a channel with the same name. We need
+;; this because that's the assumption that underpins the `irc/channel->server'
+;; function. This will probably be an O(n^2) operation.
+(prelude/assert
+ (set/distinct? (set/from-list
+                 (cycle/to-list
+                  (alist/get "irc.freenode.net"
+                             irc/server->channels)))
+                (set/from-list
+                 (cycle/to-list
+                  (alist/get "irc.corp.google.com"
+                             irc/server->channels)))))
+
+(defun irc/channel->server (server->channels channel)
+  "Resolve an IRC server from a given CHANNEL."
+  (let ((result (alist/find (lambda (k v) (cycle/contains? channel v))
+                            server->channels)))
+    (prelude/assert (maybe/some? result))
+    result))
+
+(defun irc/channel->cycle (server->channels channel)
+  "Resolve an IRC's channels cycle from a given CHANNEL."
+  (alist/get (irc/channel->server server->channels channel)
+             server->channels))
+
+;; Setting `erc-join-buffer' to 'bury prevents erc from stealing focus of the
+;; current buffer when it connects to IRC servers.
+(setq erc-join-buffer 'bury)
+
+;; TODO: Here is another horrible hack that should be revisted.
+(setq erc-autojoin-channels-alist
+      (->> irc/server->channels
+           (alist/map-values #'cycle/to-list)
+           (alist/map-keys (>> (s-chop-prefix "irc.")
+                               (s-chop-suffix ".net")))))
+
+(defcustom irc/install-kbds? t
+  "When t, install the keybindings defined herein.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun irc/message (x)
+  "Print message X in a structured way."
+  (message (string/format "[irc.el] %s" x)))
+
+;; TODO: Integrate Google setup with Freenode setup.
+
+;; TODO: Support function or KBD for switching to an ERC buffer.
+
+(defun irc/kill-all-erc-processes ()
+  "Kills all ERC buffers and processes."
+  (interactive)
+  (->> (erc-buffer-list)
+       (-map #'kill-buffer)))
+
+(defun irc/switch-to-erc-buffer ()
+  "Switch to an ERC buffer."
+  (interactive)
+  (let ((buffers (erc-buffer-list)))
+    (if (list/empty? buffers)
+        (error "[irc.el] No ERC buffers available")
+      (switch-to-buffer (list/head (erc-buffer-list))))))
+
+(defun irc/connect-to-freenode ()
+  "Connect to Freenode IRC."
+  (interactive)
+  (erc-ssl :server "irc.freenode.net"
+           :port 6697
+           :nick "wpcarro"
+           :password (password-store-get "programming/irc/freenode")
+           :full-name "William Carroll"))
+
+;; TODO: Handle failed connections.
+(defun irc/connect-to-google ()
+  "Connect to Google's Corp IRC using ERC."
+  (interactive)
+  (erc-ssl :server "irc.corp.google.com"
+           :port 6697
+           :nick "wpcarro"
+           :full-name "William Carroll"))
+
+;; TODO: Prefer defining these with a less homespun solution. There is a
+;; function call `erc-buffer-filter' that would be more appropriate for the
+;; implementation of `irc/next-channel' and `irc/prev-channel'.
+(defun irc/next-channel ()
+  "Join the next channel for the active server."
+  (interactive)
+  (with-current-buffer (current-buffer)
+    (let ((cycle (irc/channel->cycle irc/server->channels (buffer-name))))
+      (erc-join-channel
+       (cycle/next cycle))
+      (irc/message
+       (string/format "Current IRC channel: %s" (cycle/current cycle))))))
+
+(defun irc/prev-channel ()
+  "Join the previous channel for the active server."
+  (interactive)
+  (with-current-buffer (current-buffer)
+    (let ((cycle (irc/channel->cycle irc/server->channels (buffer-name))))
+      (erc-join-channel
+       (cycle/prev cycle))
+      (irc/message
+       (string/format "Current IRC channel: %s" (cycle/current cycle))))))
+
+(add-hook 'erc-mode-hook (disable auto-fill-mode))
+(add-hook 'erc-mode-hook (disable company-mode))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Keybindings
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when irc/install-kbds?
+  (general-define-key
+   :keymaps 'erc-mode-map
+   "<C-tab>" #'irc/next-channel
+   "<C-S-iso-lefttab>" #'irc/prev-channel))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when irc/enable-tests?
+  (prelude/assert
+   (equal
+    (irc/channel->server `(("irc.dairy.com" . ,(cycle/new "#cheese" "#milk"))
+                           ("irc.color.com" . ,(cycle/new "#red" "#blue")))
+                         "#cheese")
+    "irc.dairy.com")))
+
+(provide 'irc)
+;;; irc.el ends here
diff --git a/emacs/.emacs.d/wpc/iso.el b/emacs/.emacs.d/wpc/iso.el
new file mode 100644
index 000000000000..c9ce4a48fc71
--- /dev/null
+++ b/emacs/.emacs.d/wpc/iso.el
@@ -0,0 +1,95 @@
+;;; iso.el --- Isomorphisms in Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Providing basic isomorphisms to improve code quality.
+
+;;; Code:
+
+(require 'dotted)
+(require 'tuple)
+(require 'symbol)
+(require 'string)
+(require 'list)
+(require 'alist)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defstruct iso to from x)
+
+(defconst iso/whitelist
+  '((dotted . tuple)
+    (symbol . string))
+  "Alist representing supported isomorphisms.")
+
+(defconst iso/vertices
+  (list/concat (alist/keys iso/whitelist)
+               (alist/values iso/whitelist))
+  "List of all of the vertices in the iso graph.")
+
+(defun iso/classify (x)
+  "Return type of X."
+  (cond
+   ((string/instance? x) 'string)
+   ((symbol/instance? x) 'symbol)
+   ((dotted/instance? x) 'dotted)
+   ((tuple/instance? x)  'tuple)))
+
+(cl-defun iso/exists? (to from)
+  "Return t if an isomorphism of TO to FROM exists."
+  ;; TODO: All of this can be improved modelling this with a graph.
+  (cond
+   ;; to -> from
+   ((list/contains? to (alist/keys iso/whitelist))
+    (list/contains? from (alist/values iso/whitelist)))
+   ;; from -> to
+   ((list/contains? from (alist/keys iso/whitelist))
+    (list/contains? to (alist/values iso/whitelist)))
+   ;; doesn't exist
+   (t nil)))
+
+(progn
+  (prelude/assert
+   (iso/exists? 'symbol 'string))
+  (prelude/assert
+   (iso/exists? 'dotted 'tuple))
+  (prelude/refute
+   (iso/exists? 'dotted 'symbol))
+  (prelude/refute
+   (iso/exists? 'symbol 'list)))
+
+;; TODO: Model this as a graph.
+(defconst iso/morphisms
+  '((string .
+            '(symbol #')
+     ))
+  (list (:from 'string :to 'symbol :fn #'intern)
+        (:from 'symbol :to 'string :fn #'symbol-name)
+        )
+  "")
+
+(defun iso/to (f x)
+  "Apply F to X's to."
+  (->> x
+       iso-to))
+
+(->> (iso/new "william" :to 'symbol)
+     (iso/as-to #'symbol-name)
+     )
+
+(cl-defun iso/new (x &key to)
+  "Create a new isomorphism of X mapping to TO."
+  (let ((from (iso/classify x)))
+    (prelude/assert (iso/exists? to from))
+    (make-iso :from from
+              :to to
+              :x x)))
+
+(macros/comment
+ (iso/new "william" :to 'symbol)
+ (iso/new '(one . two) :to 'tuple))
+
+(provide 'iso)
+;;; iso.el ends here
diff --git a/emacs/.emacs.d/wpc/ivy-clipmenu.el b/emacs/.emacs.d/wpc/ivy-clipmenu.el
new file mode 100644
index 000000000000..f3896137bd9f
--- /dev/null
+++ b/emacs/.emacs.d/wpc/ivy-clipmenu.el
@@ -0,0 +1,134 @@
+;;; ivy-clipmenu.el --- Emacs client for clipmenu -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Ivy integration with the clipboard manager, clipmenu.  Essentially, clipmenu
+;; turns your system clipboard into a list.
+;;
+;; To use this module, you must first install clipmenu and ensure that the
+;; clipmenud daemon is running.  Refer to the installation instructions at
+;; github.com/cdown/clipmenu for those details.
+;;
+;; This module intentionally does not define any keybindings since I'd prefer
+;; not to presume my users' preferences.  Personally, I use EXWM as my window
+;; manager, so I call `exwm-input-set-key' and map it to `ivy-clipmenu/copy'.
+;;
+;; Usually clipmenu integrates with rofi or dmenu.  This Emacs module integrates
+;; with ivy.  Launch this when you want to select a clip.
+;;
+;; Clipmenu itself supports a variety of environment variables that allow you to
+;; customize its behavior.  These variables are respected herein.  If you'd
+;; prefer to customize clipmenu's behavior from within Emacs, refer to the
+;; variables defined in this module.
+;;
+;; For more information:
+;; - See `clipmenu --help`.
+;; - Visit github.com/cdown/clipmenu.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'f)
+(require 's)
+(require 'dash)
+(require 'ivy)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Variables
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defgroup ivy-clipmenu nil
+  "Ivy integration for clipmenu."
+  :group 'ivy)
+
+(defcustom ivy-clipmenu/directory
+  (or (getenv "XDG_RUNTIME_DIR")
+      (getenv "TMPDIR")
+      "/tmp")
+  "Base directory for clipmenu's data."
+  :type 'string
+  :group 'ivy-clipmenu)
+
+(defconst ivy-clipmenu/executable-version 5
+   "The major version number for the clipmenu executable.")
+
+(defconst ivy-clipmenu/cache-directory
+  (f-join ivy-clipmenu/directory
+          (format "clipmenu.%s.%s"
+                  ivy-clipmenu/executable-version
+                  (getenv "USER")))
+  "Directory where the clips are stored.")
+
+(defconst ivy-clipmenu/cache-file-pattern
+  (f-join ivy-clipmenu/cache-directory "line_cache_*")
+  "Glob pattern matching the locations on disk for clipmenu's labels.")
+
+(defcustom ivy-clipmenu/history-length
+  (or (getenv "CM_HISTLENGTH") 25)
+  "Limit the number of clips in the history.
+This value defaults to 25.")
+
+(defvar ivy-clipmenu/history nil
+  "History for `ivy-clipmenu/copy'.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun ivy-clipmenu/parse-content (x)
+  "Parse the label from the entry in clipmenu's line-cache."
+  (->> (s-split " " x)
+       (-drop 1)
+       (s-join " ")))
+
+(defun ivy-clipmenu/list-clips ()
+  "Return a list of the content of all of the clips."
+  (->> ivy-clipmenu/cache-file-pattern
+       f-glob
+       (-map (lambda (path)
+               (s-split "\n" (f-read path) t)))
+       -flatten
+       (-reject #'s-blank?)
+       (-sort #'string>)
+       (-map #'ivy-clipmenu/parse-content)
+       delete-dups
+       (-take ivy-clipmenu/history-length)))
+
+(defun ivy-clipmenu/checksum (content)
+  "Return the CRC checksum of CONTENT."
+  (s-trim-right
+   (with-temp-buffer
+     (call-process "/bin/bash" nil (current-buffer) nil "-c"
+                   (format "cksum <<<'%s'" content))
+     (buffer-string))))
+
+(defun ivy-clipmenu/line-to-content (line)
+  "Map the chosen LINE from the line cache its content from disk."
+  (->> line
+       ivy-clipmenu/checksum
+       (f-join ivy-clipmenu/cache-directory)
+       f-read))
+
+(defun ivy-clipmenu/do-copy (x)
+  "Copy string, X, to the system clipboard."
+  (kill-new x)
+  (message "[ivy-clipmenu.el] Copied!"))
+
+(defun ivy-clipmenu/copy ()
+  "Use `ivy-read' to select and copy a clip.
+It's recommended to bind this function to a globally available keymap."
+  (interactive)
+  (let ((ivy-sort-functions-alist nil))
+    (ivy-read "Clipmenu: "
+              (ivy-clipmenu/list-clips)
+              :history 'ivy-clipmenu/history
+              :action (lambda (line)
+                        (->> line
+                             ivy-clipmenu/line-to-content
+                             ivy-clipmenu/do-copy)))))
+
+(provide 'ivy-clipmenu)
+;;; ivy-clipmenu.el ends here
diff --git a/emacs/.emacs.d/wpc/ivy-helpers.el b/emacs/.emacs.d/wpc/ivy-helpers.el
new file mode 100644
index 000000000000..c71a907a20c1
--- /dev/null
+++ b/emacs/.emacs.d/wpc/ivy-helpers.el
@@ -0,0 +1,31 @@
+;;; ivy-helpers.el --- More interfaces to ivy -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Hopefully to improve my workflows.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'alist)
+(require 'tuple)
+(require 'string)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defun ivy-helpers/kv (prompt kv f)
+  "PROMPT users with the keys in KV and return its corresponding value.  Calls F
+with the key and value from KV."
+  (ivy-read
+   prompt
+   kv
+   :require-match t
+   :action (lambda (entry)
+             (funcall f (car entry) (cdr entry)))))
+
+;;; Code:
+(provide 'ivy-helpers)
+;;; ivy-helpers.el ends here
diff --git a/emacs/.emacs.d/wpc/kaomoji.el b/emacs/.emacs.d/wpc/kaomoji.el
new file mode 100644
index 000000000000..d6d509c14667
--- /dev/null
+++ b/emacs/.emacs.d/wpc/kaomoji.el
@@ -0,0 +1,45 @@
+;;; kaomoji.el --- Supporting kaomoji usage -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Simple keyboards like this make life a bit better.
+
+;;; Code:
+
+(defvar kaomoji/install-kbds?
+  nil
+  "Set to t if you'd like the keybindings to be installed.")
+
+(defconst kaomoji/symbols '(("Joy" . "(⌒‿⌒)")
+                    ("Love" . "(ღ˘⌣˘ღ)")
+                    ("Sympathy" . "ヽ(~_~(・_・ )ゝ")
+                    ("Dissatisfaction" . "(>﹏<)")
+                    ("Anger" . "ヽ(‵﹏´)ノ")
+                    ("Hugging" . "(づ ̄ ³ ̄)づ")
+                    ("Hiding" . "┬┴┬┴┤( ͡° ͜ʖ├┬┴┬┴")
+                    ("Sleeping" . "(-_-) zzZ")
+                    ("Embarrassed" . "(×﹏×)")
+                    ("Shrug" . "ヽ(ー_ー )ノ"))
+  "Alist of human-readable emotions to the kaomoji.")
+
+;; TODO: Consider supporting a hydra for these.
+
+(defun kaomoji/select ()
+  "Interactively select a kaomoji and copy it to the clipboard."
+  (interactive)
+  (ivy-read
+   "Select a kaomoji: "
+   kaomoji/symbols
+   :action (lambda (entry)
+             (kill-new (cdr entry))
+             (alert "Copied to clipboard!"))))
+
+;; TODO: Define Hydra for all custom keyboards.
+;; TODO: Define a better keybinding in a different keymap.
+(when kaomoji/install-kbds?
+  (general-define-key
+   :keymaps 'global
+   "M-k" #'kaomoji/select))
+
+(provide 'kaomoji)
+;;; kaomoji.el ends here
diff --git a/emacs/.emacs.d/wpc/kbd.el b/emacs/.emacs.d/wpc/kbd.el
new file mode 100644
index 000000000000..49b346bc6ea8
--- /dev/null
+++ b/emacs/.emacs.d/wpc/kbd.el
@@ -0,0 +1,90 @@
+;;; kbd.el --- Elisp keybinding -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; In order to stay organized, I'm attempting to dedicate KBD prefixes to
+;; specific functions.  I'm hoping I can be more deliberate with my keybinding
+;; choices this way.
+;;
+;; Terminology:
+;; For a more thorough overview of the terminology refer to `keybindings.md'
+;; file.  Here's a brief overview:
+;; - workspace: Anything concerning EXWM workspaces.
+;; - x11: Anything concerning X11 applications.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'alist)
+(require 'set)
+(require 'string)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst kbd/install-kbds? t
+  "When t, install keybindings defined herein.")
+
+(defconst kbd/prefixes
+  '((workspace . "s")
+    (x11 . "C-s"))
+  "Mapping of functions to designated keybinding prefixes to stay organized.")
+
+;; Assert that no keybindings are colliding.
+(prelude/assert
+ (= (alist/count kbd/prefixes)
+    (->> kbd/prefixes
+         alist/values
+         set/from-list
+         set/count)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun kbd/raw (f x)
+  "Return the string keybinding for function F and appendage X.
+Values for F include:
+- workspace
+- x11"
+  (prelude/assert (alist/has-key? f kbd/prefixes))
+  (string/format
+   "%s-%s"
+   (alist/get f kbd/prefixes)
+   x))
+
+(defun kbd/for (f x)
+  "Return the `kbd' for function F and appendage X.
+Values for F include:
+- workspace
+- x11"
+  (kbd (kbd/raw f x)))
+
+;; TODO: Prefer copying human-readable versions to the clipboard.  Right now
+;; this isn't too useful.
+(defun kbd/copy-keycode ()
+  "Copy the pressed key to the system clipboard."
+  (interactive)
+  (message "[kbd] Awaiting keypress...")
+  (let ((key (read-key)))
+    (clipboard/copy (string/format "%s" key))
+    (message (string/format "[kbd] \"%s\" copied!" key))))
+
+(defun kbd/print-keycode ()
+  "Prints the pressed keybinding."
+  (interactive)
+  (message "[kbd] Awaiting keypress...")
+  (message (string/format "[kbd] keycode: %s" (read-key))))
+
+;; (when kbd/install-kbds?
+;;   (general-define-key
+;;    :prefix "<SPC>"
+;;    "hr" #'kbd/print-keycode))
+
+(provide 'kbd)
+;;; kbd.el ends here
diff --git a/emacs/.emacs.d/wpc/keybindings.el b/emacs/.emacs.d/wpc/keybindings.el
new file mode 100644
index 000000000000..755311483dd1
--- /dev/null
+++ b/emacs/.emacs.d/wpc/keybindings.el
@@ -0,0 +1,46 @@
+;;; keybindings.el --- Centralizing my keybindings -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Attempting to centralize my keybindings to simplify my configuration.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'clipboard)
+(require 'screen-brightness)
+(require 'chrome)
+(require 'scrot)
+(require 'ivy-clipmenu)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defmacro keybinding/exwm (c fn)
+  "Bind C to FN using `exwm-input-set-key' with `kbd' applied to C."
+  `(exwm-input-set-key (kbd ,c) ,fn))
+
+(keybinding/exwm "C-M-v" #'ivy-clipmenu/copy)
+
+(keybinding/exwm "<XF86MonBrightnessUp>" #'screen-brightness/increase)
+(keybinding/exwm "<XF86MonBrightnessDown>" #'screen-brightness/decrease)
+
+(keybinding/exwm "<XF86AudioMute>" #'pulse-audio/toggle-mute)
+(keybinding/exwm "<XF86AudioLowerVolume>" #'pulse-audio/decrease-volume)
+(keybinding/exwm "<XF86AudioRaiseVolume>" #'pulse-audio/increase-volume)
+(keybinding/exwm "<XF86AudioMicMute>" #'pulse-audio/toggle-microphone)
+
+(keybinding/exwm "C-M-c" #'chrome/browse)
+
+(keybinding/exwm (kbd/raw 'x11 "s") #'scrot/select)
+
+;; TODO: I need this because my Ergodox EZ sends super+shift instead of just
+;; super. Remove this once I fix my Ergodox.
+(keybinding/exwm "C-S-s-s" #'scrot/select)
+
+(provide 'keybindings)
+;;; keybindings.el ends here
diff --git a/emacs/.emacs.d/wpc/keyboard.el b/emacs/.emacs.d/wpc/keyboard.el
new file mode 100644
index 000000000000..ec50cabd2719
--- /dev/null
+++ b/emacs/.emacs.d/wpc/keyboard.el
@@ -0,0 +1,152 @@
+;;; keyboard.el --- Managing keyboard preferences with Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Setting key repeat and other values.
+;;
+;; Be wary of suspiciously round numbers.  Especially those divisible by ten!
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'string)
+(require 'number)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Support clamping functions for repeat-{rate,delay} to ensure only valid
+;; values are sent to xset.
+(defcustom keyboard/repeat-rate 80
+  "The number of key repeat signals sent per second.")
+
+(defcustom keyboard/repeat-delay 170
+  "The number of milliseconds before autorepeat starts.")
+
+(defconst keyboard/repeat-rate-copy keyboard/repeat-rate
+  "Copy of `keyboard/repeat-rate' to support `keyboard/reset-key-repeat'.")
+
+(defconst keyboard/repeat-delay-copy keyboard/repeat-delay
+  "Copy of `keyboard/repeat-delay' to support `keyboard/reset-key-repeat'.")
+
+(defcustom keyboard/install-preferences? t
+  "When t, install keyboard preferences.")
+
+(defcustom keyboard/install-kbds? nil
+  "When t, install keybindings.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun keyboard/message (x)
+  "Message X in a structured way."
+  (message (string/format "[keyboard.el] %s" x)))
+
+(cl-defun keyboard/set-key-repeat (&key
+                                   (rate keyboard/repeat-rate)
+                                   (delay keyboard/repeat-delay))
+  "Use xset to set the key-repeat RATE and DELAY."
+  (prelude/start-process
+   :name "keyboard/set-key-repeat"
+   :command (string/format "xset r rate %s %s" delay rate)))
+
+;; NOTE: Settings like this are machine-dependent. For instance I only need to
+;; do this on my laptop and other devices where I don't have access to my split
+;; keyboard.
+;; NOTE: Running keysym Caps_Lock is not idempotent.  If this is called more
+;; than once, xmodmap will start to error about non-existent Caps_Lock symbol.
+;; For more information see here:
+;; https://unix.stackexchange.com/questions/108207/how-to-map-caps-lock-as-the-compose-key-using-xmodmap-portably-and-idempotently
+(defun keyboard/swap-caps-lock-and-escape ()
+  "Swaps the caps lock and escape keys using xmodmap."
+  (interactive)
+  ;; TODO: Ensure these work once the tokenizing in prelude/start-process works
+  ;; as expected.
+  (start-process "keyboard/swap-caps-lock-and-escape" nil "/usr/bin/xmodmap" "-e"
+                 "remove Lock = Caps_Lock")
+  (start-process "keyboard/swap-caps-lock-and-escape" nil "/usr/bin/xmodmap" "-e"
+                 "keysym Caps_Lock = Escape"))
+
+(defun keyboard/inc-repeat-rate ()
+  "Increment `keyboard/repeat-rate'."
+  (interactive)
+  (setq keyboard/repeat-rate (number/inc keyboard/repeat-rate))
+  (keyboard/set-key-repeat :rate keyboard/repeat-rate)
+  (keyboard/message
+   (string/format "Rate: %s" keyboard/repeat-rate)))
+
+(defun keyboard/dec-repeat-rate ()
+  "Decrement `keyboard/repeat-rate'."
+  (interactive)
+  (setq keyboard/repeat-rate (number/dec keyboard/repeat-rate))
+  (keyboard/set-key-repeat :rate keyboard/repeat-rate)
+  (keyboard/message
+   (string/format "Rate: %s" keyboard/repeat-rate)))
+
+(defun keyboard/inc-repeat-delay ()
+  "Increment `keyboard/repeat-delay'."
+  (interactive)
+  (setq keyboard/repeat-delay (number/inc keyboard/repeat-delay))
+  (keyboard/set-key-repeat :delay keyboard/repeat-delay)
+  (keyboard/message
+   (string/format "Delay: %s" keyboard/repeat-delay)))
+
+(defun keyboard/dec-repeat-delay ()
+  "Decrement `keyboard/repeat-delay'."
+  (interactive)
+  (setq keyboard/repeat-delay (number/dec keyboard/repeat-delay))
+  (keyboard/set-key-repeat :delay keyboard/repeat-delay)
+  (keyboard/message
+   (string/format "Delay: %s" keyboard/repeat-delay)))
+
+(defun keyboard/print-key-repeat ()
+  "Print the currently set values for key repeat."
+  (interactive)
+  (keyboard/message
+   (string/format "Rate: %s. Delay: %s"
+                  keyboard/repeat-rate
+                  keyboard/repeat-delay)))
+
+(defun keyboard/set-preferences ()
+  "Reset the keyboard preferences to their default values.
+NOTE: This function exists because occasionally I unplug and re-plug in a
+  keyboard and all of the preferences that I set using xset disappear."
+  (interactive)
+  (keyboard/swap-caps-lock-and-escape)
+  (keyboard/set-key-repeat :rate keyboard/repeat-rate
+                           :delay keyboard/repeat-delay)
+  ;; TODO: Implement this message function as a macro that pulls the current
+  ;; file name.
+  (keyboard/message "Keyboard preferences set!"))
+
+(defun keyboard/reset-key-repeat ()
+  "Set key repeat rate and delay to original values."
+  (interactive)
+  (keyboard/set-key-repeat :rate keyboard/repeat-rate-copy
+                           :delay keyboard/repeat-delay-copy)
+  (keyboard/message "Key repeat preferences reset."))
+
+(when keyboard/install-preferences?
+  (keyboard/set-preferences))
+
+;; TODO: Define minor-mode for this.
+(when keyboard/install-kbds?
+  (general-unbind 'motion "C-i" "C-y")
+  (general-define-key
+   ;; TODO: Choose better KBDs for these that don't interfere with useful evil
+   ;; ones.
+   ;; Use C-y when you accidentally send the key-repeat too high or too low to
+   ;; be meaningful.
+   "C-y" #'keyboard/reset-key-repeat
+   "C-i" #'keyboard/inc-repeat-rate
+   "C-u" #'keyboard/dec-repeat-rate
+   "C-S-i" #'keyboard/inc-repeat-delay
+   "C-S-u" #'keyboard/dec-repeat-delay))
+
+(provide 'keyboard)
+;;; keyboard.el ends here
diff --git a/emacs/.emacs.d/wpc/keymap.el b/emacs/.emacs.d/wpc/keymap.el
new file mode 100644
index 000000000000..87d340fcdbf1
--- /dev/null
+++ b/emacs/.emacs.d/wpc/keymap.el
@@ -0,0 +1,25 @@
+;;; keymap.el --- Working with Elisp keymaps -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Very much a work-in-progress.
+
+;;; Code:
+
+(require 'macros)
+(require 'symbol)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun keymap/pretty-print (x)
+  "Pretty prints `X'."
+  ;; TODO: Work-in-progress
+  (s-concat "\\{" (symbol/to-string x) "}"))
+
+(macros/comment
+ (keymap/pretty-print lispyville-mode-map))
+
+(provide 'keymap)
+;;; keymap.el ends here
diff --git a/emacs/.emacs.d/wpc/laptop-battery.el b/emacs/.emacs.d/wpc/laptop-battery.el
new file mode 100644
index 000000000000..3ec03553d2ca
--- /dev/null
+++ b/emacs/.emacs.d/wpc/laptop-battery.el
@@ -0,0 +1,60 @@
+;;; laptop-battery.el --- Display laptop battery information -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Some wrappers to obtain battery information.
+;;
+;; To troubleshoot battery consumpton look into the CLI `powertop`.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Roadmap
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Support functions that work with reporting battery stats.
+;; TODO: low-battery-reporting-threshold
+;; TODO: charged-battery-reporting-threshold
+;; TODO: Format modeline battery information.
+;; TODO: Provide better time information in the modeline.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'battery)
+(require 'alist)
+(require 'maybe)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun laptop-battery/available? ()
+  "Return t if battery information is available."
+  (maybe/some? battery-status-function))
+
+(defun laptop-battery/percentage ()
+  "Return the current percentage of the battery."
+  (->> battery-status-function
+       funcall
+       (alist/get 112)))
+
+(defun laptop-battery/print-percentage ()
+  "Return the current percentage of the battery."
+  (interactive)
+  (->> (laptop-battery/percentage)
+       message))
+
+(defun laptop-battery/display ()
+  "Display laptop battery percentage in the modeline."
+  (interactive)
+  (display-battery-mode 1))
+
+(defun laptop-battery/hide ()
+  "Hide laptop battery percentage in the modeline."
+  (interactive)
+  (display-battery-mode -1))
+
+(provide 'laptop-battery)
+;;; laptop-battery.el ends here
diff --git a/emacs/.emacs.d/wpc/list.el b/emacs/.emacs.d/wpc/list.el
new file mode 100644
index 000000000000..5a63c8bd94e0
--- /dev/null
+++ b/emacs/.emacs.d/wpc/list.el
@@ -0,0 +1,235 @@
+;;; list.el --- Functions for working with lists. -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Since I prefer having the `list/' namespace, I wrote this module to wrap many
+;; of the functions that are defined in the the global namespace in ELisp.  I
+;; sometimes forget the names of these functions, so it's nice for them to be
+;; organized like this.
+;;
+;; Motivation:
+;; Here are some examples of function names that I cannot tolerate:
+;; - `car': Return the first element (i.e. "head") of a linked list
+;; - `cdr': Return the tail of a linked list
+
+;; As are most APIs for standard libraries that I write, this is heavily
+;; influenced by Elixir's standard library.
+;;
+;; Elixir's List library:
+;; - ++/2
+;; - --/2
+;; - hd/1
+;; - tl/1
+;; - in/2
+;; - length/1
+;;
+;; Similar libraries:
+;; - dash.el: Functional library that mimmicks Clojure.  It is consumed herein.
+;; - list-utils.el: Utility library that covers things that dash.el may not
+;;   cover.
+;;   stream.el: Elisp implementation of streams, "implemented as delayed
+;;   evaluation of cons cells."
+
+;; TODO: Consider naming this file linked-list.el.
+
+;; TODO: Support module-like macro that auto-namespaces functions.
+
+;; TODO: Consider wrapping most data structures like linked-lists,
+;; associative-lists, etc in a `cl-defstruct', so that the dispatching by type
+;; can be nominal instead of duck-typing.  I'm not sure if this is a good idea
+;; or not.  If I do this, I should provide isomorphisms to map between idiomatic
+;; ways of working with Elisp data structures and my wrapped variants.
+
+;; TODO: Are function aliases/synonyms even a good idea?  Or do they just
+;; bloat the API unnecessarily?
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Move `prelude/assert' elsewhere so that I can require it without
+;; introducing the circular dependency of list.el -> prelude.el -> list.el.
+;;(require 'prelude)
+(require 'dash)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst list/tests? t
+  "When t, run the test suite.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun list/new ()
+  "Return a new, empty list."
+  '())
+
+(defun list/concat (&rest lists)
+  "Joins `LISTS' into on list."
+  (apply #'-concat lists))
+
+(defun list/join (joint xs)
+  "Join a list of strings, XS, with JOINT."
+  (if (list/empty? xs)
+      ""
+    (list/reduce (list/first xs)
+                 (lambda (x acc)
+                   (string/concat acc joint x))
+                 (list/tail xs))))
+
+(defun list/length (xs)
+  "Return the number of elements in `XS'."
+  (length xs))
+
+(defun list/get (i xs)
+  "Return the value in `XS' at `I', or nil."
+  (nth i xs))
+
+(defun list/head (xs)
+  "Return the head of `XS'."
+  (car xs))
+
+;; TODO: Learn how to write proper function aliases.
+(defun list/first (xs)
+  "Alias for `list/head' for `XS'."
+  (list/head xs))
+
+(defun list/tail (xs)
+  "Return the tail of `XS'."
+  (cdr xs))
+
+(defun list/reverse (xs)
+  "Reverses `XS'."
+  (reverse xs))
+
+(defun list/cons (x xs)
+  "Add `X' to the head of `XS'."
+  (cons x xs))
+
+;; map, filter, reduce
+
+;; TODO: Create function adapters like swap.
+;; (defun adapter/swap (f)
+;;   "Return a new function that wraps `F' and swaps the arguments."
+;;   (lambda (a b)
+;;     (funcall f b a)))
+
+;; TODO: Make this function work.
+(defun list/reduce (acc f xs)
+  "Return over `XS' calling `F' on an element in `XS'and `ACC'."
+  (-reduce-from (lambda (acc x) (funcall f x acc)) acc xs))
+
+;; TODO: Support this. It seems like `alist/set' is not working as I expected it
+;; to. Perhaps we should add some tests to confirm the expected behavior.
+;; (cl-defun list/index (f xs &key (transform (lambda (x) x)))
+;;   "Return a mapping of F applied to each x in XS to TRANSFORM applied to x.
+;; The TRANSFORM function defaults to the identity function."
+;;   (->> xs
+;;        (list/reduce (alist/new)
+;;                     (lambda (x acc)
+;;                       (let ((k (funcall f x))
+;;                             (v (funcall transform x)))
+;;                         (if (alist/has-key? k acc)
+;;                             (setf (alist-get k acc) (list v))
+;;                           (setf (alist-get k acc) (list v))))))))
+;; (prelude/assert
+;;  (equal '(("John" . ("Cleese" "Malkovich"))
+;;           ("Thomas" . ("Aquinas")))
+;;         (list/index (lambda (x) (plist-get x :first-name))
+;;                     '((:first-name "John" :last-name "Cleese")
+;;                       (:first-name "John" :last-name "Malkovich")
+;;                       (:first-name "Thomas" :last-name "Aquinas"))
+;;                     :transform (lambda (x) (plist-get x :last-name)))))
+
+(defun list/map (f xs)
+  "Call `F' on each element of `XS'."
+  (-map f xs))
+
+(defun list/map-indexed (f xs)
+  "Call `F' on each element of `XS' along with its index."
+  (-map-indexed (lambda (i x) (funcall f x i)) xs))
+
+(defun list/filter (p xs)
+  "Return a subset of XS where predicate P returned t."
+  (list/reverse
+   (list/reduce
+    '()
+    (lambda (x acc)
+      (if (funcall p x)
+          (list/cons x acc)
+        acc))
+    xs)))
+
+(defun list/reject (p xs)
+  "Return a subset of XS where predicate of P return nil."
+  (list/filter (lambda (x) (not (funcall p x))) xs))
+
+(defun list/find (p xs)
+  "Return the first x in XS that passes P or nil."
+  (-find p xs))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun list/instance? (xs)
+  "Return t if `XS' is a list.
+Be leery of using this with things like alists.  Many data structures in Elisp
+  are implemented using linked lists."
+  (listp xs))
+
+(defun list/empty? (xs)
+  "Return t if XS are empty."
+  (= 0 (list/length xs)))
+
+(defun list/all? (p xs)
+  "Return t if all `XS' pass the predicate, `P'."
+  (-all? p xs))
+
+(defun list/any? (p xs)
+  "Return t if any `XS' pass the predicate, `P'."
+  (-any? p xs))
+
+(defun list/contains? (x xs)
+  "Return t if X is in XS using `equal'."
+  (-contains? xs x))
+
+;; TODO: Support dedupe.
+;; TODO: Should we call this unique? Or distinct?
+
+;; TODO: Add tests.
+(defun list/dedupe-adjacent (xs)
+  "Return XS without adjacent duplicates."
+  (prelude/assert (not (list/empty? xs)))
+  (list/reduce (list (list/first xs))
+    (lambda (x acc)
+      (if (equal x (list/first acc))
+          acc
+        (list/cons x acc)))
+    xs))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; (when list/tests?
+;;   (prelude/assert
+;;    (= 0
+;;       (list/length '())))
+;;   (prelude/assert
+;;    (= 5
+;;       (list/length '(1 2 3 4 5))))
+;;   (prelude/assert
+;;    (= 16
+;;       (list/reduce 1 (lambda (x acc) (+ x acc)) '(1 2 3 4 5))))
+;;   (prelude/assert
+;;    (equal '(2 4 6 8 10)
+;;           (list/map (lambda (x) (* x 2)) '(1 2 3 4 5)))))
+
+(provide 'list)
+;;; list.el ends here
diff --git a/emacs/.emacs.d/wpc/list.nix b/emacs/.emacs.d/wpc/list.nix
new file mode 100644
index 000000000000..e664ba6fd4a1
--- /dev/null
+++ b/emacs/.emacs.d/wpc/list.nix
@@ -0,0 +1,8 @@
+{ pkgs ? import (builtins.fetchTarball
+  "https://github.com/tazjin/depot/archive/master.tar.gz") {} }:
+
+pkgs.writeElispBin {
+  name = "list";
+  deps = epkgs: [ epkgs.dash ./prelude.nix ];
+  src = ./list.el;
+}
diff --git a/emacs/.emacs.d/wpc/macros.el b/emacs/.emacs.d/wpc/macros.el
new file mode 100644
index 000000000000..5f7c93902e3e
--- /dev/null
+++ b/emacs/.emacs.d/wpc/macros.el
@@ -0,0 +1,95 @@
+;;; macros.el --- Helpful variables for making my ELisp life more enjoyable -*- lexical-binding: t -*-
+;; Authpr: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; This file contains helpful variables that I use in my ELisp development.
+
+;; TODO: Consider a macro solution for mimmicking OCaml's auto resolution of
+;; dependencies using `load-path' and friends.
+
+;;; Code:
+
+(require 'f)
+(require 'string)
+(require 'symbol)
+
+;; TODO: Support `xi' lambda shorthand macro.
+
+(defmacro enable (mode)
+  "Helper for enabling `MODE'.
+Useful in `add-hook' calls.  Some modes, like `linum-mode' need to be called as
+`(linum-mode 1)', so `(add-hook mode #'linum-mode)' won't work."
+  `#'(lambda nil (,mode 1)))
+
+(defmacro disable (mode)
+  "Helper for disabling `MODE'.
+Useful in `add-hook' calls."
+  `#'(lambda nil (,mode -1)))
+
+(defmacro add-hooks (modes callback)
+  "Add multiple `MODES' for the `CALLBACK'.
+Usage: (add-hooks '(one-mode-hook 'two-mode-hook) #'fn)"
+  `(dolist (mode ,modes)
+     (add-hook mode ,callback)))
+
+(defmacro add-hook-before-save (mode f)
+  "Register a hook, `F', for a mode, `MODE' more conveniently.
+Usage: (add-hook-before-save 'reason-mode-hook #'refmt-before-save)"
+  `(add-hook ,mode
+             (lambda ()
+               (add-hook 'before-save-hook ,f))))
+
+;; TODO: Debug.
+(defmacro macros/ilambda (&rest body)
+  "Surrounds `BODY' with an interactive lambda function."
+  `(lambda ()
+     (interactive)
+     ,@body))
+
+;; TODO: Privatize?
+(defun namespace ()
+  "Return the namespace for a function based on the filename."
+  (->> (buffer-file-name)
+       f-filename
+       f-base))
+
+(defmacro macros/comment (&rest _)
+  "Empty comment s-expresion where `BODY' is ignored."
+  `nil)
+
+;; NOTE: Not prepending the "macros" to this macro, since brevity is its goal.
+(defmacro >> (&rest forms)
+  "Compose a new, point-free function by composing FORMS together."
+  (let ((sym (gensym)))
+    `(lambda (,sym)
+       (->> ,sym ,@forms))))
+
+;; TOOD: Support this.
+(cl-defmacro macros/test
+    (&key function
+          test
+          args
+          expect
+          equality)
+  (let* ((namespace (namespace))
+         (test-name (string/->symbol
+                     (s-concat namespace
+                               "/"
+                               "test"
+                               "/"
+                               (s-chop-prefix
+                                (s-concat namespace "/")
+                                (symbol/to-string function))))))
+    `(ert-deftest ,test-name ()
+       ,test
+       (should (,equality (apply ,function ,args)
+                        ,expect)))))
+
+(defmacro macros/support-file-extension (ext mode)
+  "Register MODE to automatically load with files ending with EXT extension.
+Usage: (macros/support-file-extension \"pb\" protobuf-mode)"
+  (let ((extension (string/format "\\.%s\\'" ext)))
+    `(add-to-list 'auto-mode-alist '(,extension . ,mode))))
+
+(provide 'macros)
+;;; macros.el ends here
diff --git a/emacs/.emacs.d/wpc/math.el b/emacs/.emacs.d/wpc/math.el
new file mode 100644
index 000000000000..3176d906b466
--- /dev/null
+++ b/emacs/.emacs.d/wpc/math.el
@@ -0,0 +1,59 @@
+;;; math.el --- Math stuffs -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Containing some useful mathematical functions.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'maybe)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst math/pi pi
+  "The number pi.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Support all three arguments.
+;; Int -> Int -> Int -> Boolean
+(cl-defun math/triangle-of-power (&key base power result)
+  ;; TODO: Assert two of three are set.
+  (cond
+   ((maybe/somes? base power result)
+    (error "All three arguments should not be set"))
+   ((maybe/somes? power result)
+    (message "power and result"))
+   ((maybe/somes? base result)
+    (log result base))
+   ((maybe/somes? base power)
+    (expt base power))
+   (t
+    (error "Two of the three arguments must be set"))))
+
+(defun math/mod (x y)
+  "Return X mod Y."
+  (mod x y))
+
+(defun math/exp (x y)
+  "Return X raised to the Y."
+  (expt x y))
+
+(defun math/round (x)
+  "Round X to nearest ones digit."
+  (round x))
+
+(defun math/floor (x)
+  "Floor value X."
+  (floor x))
+
+(provide 'math)
+;;; math.el ends here
diff --git a/emacs/.emacs.d/wpc/maybe.el b/emacs/.emacs.d/wpc/maybe.el
new file mode 100644
index 000000000000..0973b1ed65f7
--- /dev/null
+++ b/emacs/.emacs.d/wpc/maybe.el
@@ -0,0 +1,102 @@
+;;; maybe.el --- Library for dealing with nil values -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Inspired by Elm's Maybe library.
+;;
+;; For now, a Nothing value will be defined exclusively as a nil value.  I'm
+;; uninterested in supported falsiness in this module even at risk of going
+;; against the LISP grain.
+;;
+;; I'm avoiding introducing a struct to handle the creation of Just and Nothing
+;; variants of Maybe.  Perhaps this is a mistake in which case this file would
+;; be more aptly named nil.el.  I may change that.  Because of this limitation,
+;; functions in Elm's Maybe library like andThen, which is the monadic bind for
+;; the Maybe type, doesn't have a home here since we cannot compose multiple
+;; Nothing or Just values without a struct or some other construct.
+;;
+;; Possible names for the variants of a Maybe.
+;; None    | Some
+;; Nothing | Something
+;; None    | Just
+;; Nil     | Set
+;;
+;; NOTE: In Elisp, values like '() (i.e. the empty list) are aliases for nil.
+;; What else in Elisp is an alias in this way?
+;; Examples:
+;; TODO: Provide examples of other nil types in Elisp.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'list)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar maybe/test? t
+  "When t, run the test suite defined herein.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun maybe/nil? (x)
+  "Return t if X is nil."
+  (eq nil x))
+
+(defun maybe/some? (x)
+  "Return t when X is non-nil."
+  (not (maybe/nil? x)))
+
+(defun maybe/nils? (&rest xs)
+  "Return t if all XS are nil."
+  (list/all? #'maybe/nil? xs))
+
+(defun maybe/somes? (&rest xs)
+  "Return t if all XS are non-nil."
+  (list/all? #'maybe/some? xs))
+
+(defun maybe/default (default x)
+  "Return DEFAULT when X is nil."
+  (if (maybe/nil? x) default x))
+
+(defun maybe/map (f x)
+  "Apply F to X if X is not nil."
+  (if (maybe/some? x)
+      (funcall f x)
+    x))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when maybe/test?
+  ;; nil?
+  (prelude/assert (maybe/nil? nil))
+  (prelude/refute (maybe/nil? t))
+  ;; some?
+  (prelude/assert (maybe/some? 10))
+  (prelude/refute (maybe/some? nil))
+  ;; nils?
+  (prelude/assert (maybe/nils? nil nil nil nil))
+  (prelude/refute (maybe/nils? nil t nil t))
+  ;; somes?
+  (prelude/assert (maybe/somes? t 10 '(1 2 3) "some"))
+  (prelude/refute (maybe/somes? t nil '(1 2 3) "some"))
+  ;; default
+  (prelude/assert
+   (and (= 0 (maybe/default 5 0))
+        (= 5 (maybe/default 5 nil))))
+  ;; map
+  (prelude/assert
+   (and (= 2 (maybe/map #'1+ 1))
+        (eq nil (maybe/map #'1+ nil)))))
+
+(provide 'maybe)
+;;; maybe.el ends here
diff --git a/emacs/.emacs.d/wpc/me-seconds.el b/emacs/.emacs.d/wpc/me-seconds.el
new file mode 100644
index 000000000000..f03e5d07d790
--- /dev/null
+++ b/emacs/.emacs.d/wpc/me-seconds.el
@@ -0,0 +1,245 @@
+;;; me-seconds.el --- How valuable is my time? -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Inspired by Google's concept of SWE-seconds, I decided to try and compute how
+;; value my personal time is.
+;;
+;; This library should integrate with another library that handles currency
+;; conversions using locally cached data for historial values and network
+;; requests for current values.
+;;
+;; Context sensitivity:
+;; Many of the values herein are based on my values that are a function of the
+;; year, my current salary, my current company holiday policy, and my current
+;; country holiday policy.  As such, many of these constants need to be updated
+;; whenever changes occur in order for these functions to be useful.
+;;
+;; Units of time:
+;; - seconds
+;; - minutes
+;; - hours
+;; - days
+;; - weeks
+;; - months
+;; - years
+;;
+;; Wish list:
+;; - I should create a money.el struct to work with herein.  This module would
+;;   expose basic algebra for working with money structs, which would be handy.
+;; - I should create a time.el struct for working with hours in the day.  I'd
+;;   like to be able to do (+ 9:15 17:45) cleanly.
+;;
+;; Terminology:
+;; SWE hours give an order of magnitude approximation to the cost of resources
+;; in dollars per hour at 2115 hours per year.
+;; - SWE hour (SWEh)
+;; - SWE year (SWEy)
+;; - SWE nominal
+;; - SWE opportunity
+;;
+;; Other isomorphisms include:
+;; - Borg GCU
+;; - Borg RAM
+;; - Tape (library)
+;; - Tape (vault)
+;; - Spindles (low latency)
+;; - Spindles (throughput)
+;; - Spindles (throughput)
+;; - Tape (throughput)
+;; - SWE (nominal)
+;; - SWE (opportunity)
+
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'macros)
+(require 'string)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun me-seconds/salary (amt)
+  "Return the yearly rate of AMT of money in GBP.
+f :: Integer -> Rate"
+  (make-rate :money (make-money :whole amt :fractional 0 :currency 'GBP)
+             :unit 'year))
+
+(defconst me-seconds/salary (me-seconds/salary 80000)
+  "My salary in GBP.")
+
+;; TODO: Consider changing these into units of time.
+(defconst me-seconds/months-per-year 12
+  "Number of months in a year.")
+
+(defconst me-seconds/days-per-year 365
+  "Number of days in a year.")
+
+(defconst me-seconds/hours-per-year (* 24 me-seconds/days-per-year)
+  "Number of hours in a year.")
+
+(defconst me-seconds/minutes-per-year (* 60 me-seconds/hours-per-year)
+  "Number of minutes in a year.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Vacation
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst me-seconds/bank-holidays-per-year 8
+  "Number of bank holidays in the UK each year.")
+
+(defconst me-seconds/pto-days-vacation-per-year 25
+  "Number of days of paid-time-off I receive each year in the UK.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Sleeping
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst me-seconds/sleeping-hours-per-day 8
+  "An approximation of the number of hours I sleep each night on average.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Waking
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst me-seconds/waking-hours-per-day
+  (- 24 me-seconds/sleeping-hours-per-night)
+  "An approximation of the number of hours I sleep each night on average.")
+
+;; TODO: Adjust this for vacation time.
+(defconst me-seconds/waking-hours-per-year
+  (* me-seconds/waking-hours-per-day me-seconds/days-per-year)
+  "The number of hours that I work each year.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Working
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst me-seconds/working-hours-per-day
+  (- 17 9)
+  "An approximation of the number of hours I work each weekday on average.
+Note that this differs from the assumed SWE hours per day calculation, which
+  assumes 9 working hours.  See the discussion about this of go/rules-of-thumb.")
+
+(defconst me-seconds/working-hours-per-year 2115
+  "This number is borrowed from go/rules-of-thumb.")
+
+;; Keep in mind that the following classifications of time:
+;; - 9:00-17:00 M-F. Is this more expensive than time sleeping?
+;; - Weekend
+;; - Weekday
+;; - Working hours
+;; - Waking hours
+;; - Sleeping hours
+;; - Vacation hours
+;;
+;; TODO: Consider tax implications (i.e. after-tax amounts and pre-tax amounts).
+;;
+;; Should these all be treated the same since they all pull from the same pot of
+;; time? Or perhaps there are multiples involved? Much to think about. How does
+;; Google handle this?
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Supported currencies:
+;; - GBP
+;; NOTE: Amount is an integer.
+(cl-defstruct money whole fractional currency)
+(cl-defstruct rate money unit)
+
+;; TODO: Add to money.el.
+(defun money/to-string (x)
+  "Return the string representation of X.
+f :: Money -> String"
+  (let ((currency (money-currency x))
+        (whole (int-to-string (money-whole x)))
+        (fract (int-to-string (money-fractional x))))
+    (pcase currency
+      ('GBP (string/concat "£" whole "." fract))
+      ('USD (string/concat "$" whole "." fract))
+      (_ (error (string/concat
+                 "Currency: \""
+                 (symbol-name currency)
+                 "\" not supported"))))))
+
+(macros/comment
+ (money/to-string
+  (make-money :whole 100 :fractional 99 :currency 'GBP)))
+
+;; TODO: Add to rate.el.
+(defun rate/to-string (x)
+  "Message X as a rate.
+f :: Rate -> String"
+  (string/concat
+   (money/to-string (rate-money x))
+   " / "
+   (pcase (rate-unit x)
+     ('second "sec")
+     ('minute "min")
+     ('hour   "hr")
+     ('day    "day")
+     ('week   "week")
+     ('month  "month")
+     ('year   "year"))))
+
+(macros/comment
+ (rate/to-string
+  (make-rate
+   :money (make-money :whole 10 :fractional 10 :currency 'GBP)
+   :unit 'day)))
+
+;; TODO: Move this to math.el?
+(defun ensure-float (x)
+  "Ensures X is treated as a float."
+  (+ 0.0 x))
+
+;; TODO: Move these to basic time mapping module.
+;; TODO: Consider making this an isomorphism.
+(defun minutes/to-hours (x)
+  "Convert X minutes to n hours."
+  (/ x 60.0))
+
+(defun hours/to-minutes (x)
+  "Convert X hours to n minutes."
+  (* x 60))
+
+(defun days/to-minutes (x)
+  "Convert X days to n minutes."
+  (* x 24 60))
+
+(defun weeks/to-minutes (x)
+  "Convert X weeks to n minutes."
+  (* x 7 24 60))
+
+(defun months/to-minutes (x)
+  "Convert X months to n minutes.
+This approximates the number of days in a month to 30."
+  (* x 30 24 60))
+
+;; TODO: Support algebraic functions with money structs.
+;; TODO: Support isomorphisms for rates to other units of time.  That would
+;; subsume most of this module's use.
+(defun me-seconds/value-per-minute (salary)
+  "Computes my value per minute based on my current SALARY.
+Signature: f :: Rate -> Rate
+This is assuming that all of my time is equally valuable.  See the above
+  discussion about the various classifications of my time.")
+
+;; TODO: See note above about isomorphisms between various rates.
+(defun me-seconds/value (salary x)
+  "Compute the value of X minutes of my time at my current SALARY.
+f :: Rate -> Integer -> Money")
+
+(macros/comment
+ (rate/to-string me-seconds/salary)
+ )
+
+(provide 'me-seconds)
+;;; me-seconds.el ends here
diff --git a/emacs/.emacs.d/wpc/monoid.el b/emacs/.emacs.d/wpc/monoid.el
new file mode 100644
index 000000000000..401d63c41728
--- /dev/null
+++ b/emacs/.emacs.d/wpc/monoid.el
@@ -0,0 +1,30 @@
+;;; monoid.el --- Working with Monoids in Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; The day has finally arrived where I'm using Monoids in Elisp.
+;;
+;; The monoid typeclass is as follows:
+;; - empty :: a
+;; - concat :: (list a) -> a
+
+;;; Code:
+
+;; TODO: Consider a prelude version that works for all Elisp types.
+(defun monoid/classify (xs)
+  "Return the type of `XS'."
+  (cond
+   ((listp xs) 'list)
+   ((vectorp xs) 'vector)
+   ((stringp xs) 'string)))
+
+
+(defun monoid/empty (xs)
+  "Return the empty monoid for the type `XS'."
+  (pcase (monoid/classify xs)
+    ('list '())
+    ('vector [])
+    ('string "")))
+
+(provide 'monoid)
+;;; monoid.el ends here
diff --git a/emacs/.emacs.d/wpc/number.el b/emacs/.emacs.d/wpc/number.el
new file mode 100644
index 000000000000..f496349050d9
--- /dev/null
+++ b/emacs/.emacs.d/wpc/number.el
@@ -0,0 +1,153 @@
+;;; number.el --- Functions for working with numbers -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;;
+;; Classifications of numbers:
+;; - Natural: (a.k.a positive integers, counting numbers); {1, 2, 3, ... }
+;;
+;; - Whole: Natural Numbers, plus zero; {0, 1, 2, 3, ...}
+;;
+;; - Integers: Whole numbers plus all the negatives of the natural numbers;
+;;   {... , -2, -1, 0, 1, 2, ...}
+;;
+;; - Rational numbers: (a.k.a. fractions) where the top and bottom numbers are
+;;   integers; e.g., 1/2, 3/4, 7/2, ⁻4/3, 4/1.  Note: The denominator cannot be
+;;   0, but the numerator can be.
+;;
+;; - Real numbers: All numbers that can be written as a decimal.  This includes
+;;   fractions written in decimal form e.g., 0.5, 0.75 2.35, ⁻0.073, 0.3333, or
+;;   2.142857. It also includes all the irrational numbers such as π, √2 etc.
+;;   Every real number corresponds to a point on the number line.
+;;
+;; The functions defined herein attempt to capture the mathematical definitions
+;; of numbers and their classifications as defined above.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'dash)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst number/test? t
+  "When t, run the test suite defined herein.")
+
+;; TODO: What about int.el?
+
+;; TODO: How do we handle a number typeclass?
+
+(defun number/positive? (x)
+  "Return t if `X' is a positive number."
+  (> x 0))
+
+(defun number/negative? (x)
+  "Return t if `X' is a positive number."
+  (< x 0))
+
+;; TODO: Don't rely on this. Need to have 10.0 and 10 behave similarly.
+(defun number/float? (x)
+  "Return t if `X' is a floating point number."
+  (floatp x))
+
+(defun number/natural? (x)
+  "Return t if `X' is a natural number."
+  (and (number/positive? x)
+       (not (number/float? x))))
+
+(defun number/whole? (x)
+  "Return t if `X' is a whole number."
+  (or (= 0 x)
+      (number/natural? x)))
+
+(defun number/integer? (x)
+  "Return t if `X' is an integer."
+  (or (number/whole? x)
+      (number/natural? (- x))))
+
+;; TODO: How defensive should these guards be?  Should we assert that the inputs
+;; are integers before checking evenness or oddness?
+
+;; TODO: Look up Runar (from Unison) definition of handling zero as even or odd.
+
+;; TODO: How should rational numbers be handled? Lisp is supposedly famous for
+;; its handling of rational numbers.
+;; TODO: `calc-mode' supports rational numbers as "1:2" meaning "1/2"
+;; (defun number/rational? (x))
+
+;; TODO: Can or should I support real numbers?
+;; (defun number/real? (x))
+
+(defun number/even? (x)
+  "Return t if `X' is an even number."
+  (or (= 0 x)
+      (= 0 (mod x 2))))
+
+(defun number/odd? (x)
+  "Return t if `X' is an odd number."
+  (not (number/even? x)))
+
+(defun number/dec (x)
+  "Subtract one from `X'.
+While this function is undeniably trivial, I have unintentionally done (- 1 x)
+  when in fact I meant to do (- x 1) that I figure it's better for this function
+  to exist, and for me to train myself to reach for it and its inc counterpart."
+  (- x 1))
+
+(defun number/inc (x)
+  "Add one to `X'."
+  (+ x 1))
+
+;; TODO: Does this belong in a math module?  Is math too vague?  Or is number
+;; too vague?
+;; TODO: Resolve the circular dependency that this introduces with series.el,
+;; and then re-enable this function and its tests below.
+;; (defun number/factorial (x)
+;;   "Return factorial of `X'."
+;;   (cond
+;;    ((number/negative? x) (error "Will not take factorial of negative numbers"))
+;;    ((= 0 x) 1)
+;;    ;; NOTE: Using `series/range' introduces a circular dependency because:
+;;    ;; series -> number -> series.  Conceptually, however, this should be
+;;    ;; perfectly acceptable.
+;;    (t (->> (series/range 1 x)
+;;            (list/reduce 1 #'*)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when number/test?
+  (prelude/assert
+   (number/positive? 10))
+  (prelude/assert
+   (number/natural? 10))
+  (prelude/assert
+   (number/whole? 10))
+  (prelude/assert
+   (number/whole? 0))
+  (prelude/assert
+   (number/integer? 10))
+  ;; (prelude/assert
+  ;;  (= 120 (number/factorial 5)))
+  (prelude/assert
+   (number/even? 6))
+  (prelude/refute
+   (number/odd? 6))
+  (prelude/refute
+   (number/positive? -10))
+  (prelude/refute
+   (number/natural? 10.0))
+  (prelude/refute
+   (number/natural? -10))
+  (prelude/refute
+   (number/natural? -10.0)))
+
+(provide 'number)
+;;; number.el ends here
diff --git a/emacs/.emacs.d/wpc/org-helpers.el b/emacs/.emacs.d/wpc/org-helpers.el
new file mode 100644
index 000000000000..ef99b18ee053
--- /dev/null
+++ b/emacs/.emacs.d/wpc/org-helpers.el
@@ -0,0 +1,29 @@
+;;; org-helpers.el --- Utility functions for working with my Org setup -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Some small utility functions intended to make me more likely to use Org mode
+;; more often.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'f)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst org-helpers/directory "~/Dropbox/org"
+  "The directory where I store most of my Org files.")
+
+(defun org-helpers/find-file (name)
+  "Call `find-file' on NAME in my org directory"
+  (find-file
+   (f-join org-helpers/directory name)))
+
+(provide 'org-helpers)
+;;; org-helpers.el ends here
diff --git a/emacs/.emacs.d/wpc/playback.el b/emacs/.emacs.d/wpc/playback.el
new file mode 100644
index 000000000000..e7ad4b2481a4
--- /dev/null
+++ b/emacs/.emacs.d/wpc/playback.el
@@ -0,0 +1,41 @@
+;;; playback.el --- Control playback with Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; As you know, my whole universe is turning Elisp, so this should too!
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun playback/prev ()
+  "Move to the previous song."
+  (interactive)
+  (prelude/start-process
+   :name "playback/prev"
+   :command "playerctl previous"))
+
+(defun playback/next ()
+  "Move to the next song."
+  (interactive)
+  (prelude/start-process
+   :name "playback/next"
+   :command "playerctl next"))
+
+(defun playback/play-pause ()
+  "Play or pause the current song."
+  (interactive)
+  (prelude/start-process
+   :name "playback/play-pause"
+   :command "playerctl play-pause"))
+
+(provide 'playback)
+;;; playback.el ends here
diff --git a/emacs/.emacs.d/wpc/polymorphism.el b/emacs/.emacs.d/wpc/polymorphism.el
new file mode 100644
index 000000000000..09045f7fb258
--- /dev/null
+++ b/emacs/.emacs.d/wpc/polymorphism.el
@@ -0,0 +1,37 @@
+;;; polymorphism.el --- Sketching my ideas for polymorphism in Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Once again: modelled after Elixir.
+
+;;; Code:
+
+;; More sketches of Elisp polymorphism initiative.
+;;
+;; Two macros:
+;; - `defprotocol'
+;; - `definstance'
+;;
+;; Is it just a coincidence that these two macros have the same number of
+;;characters or is that fate?  I say fate.
+;;
+;; (defprotocol monoid
+;;   :functions (empty concat))
+;;
+;; (definstance monoid vector
+;;   :empty
+;;   (lambda () [])
+;;   :concat
+;;   #'vector/concat)
+;;
+;; More sketching...
+;; (defun monoid/empty ()
+;;   "Sketch."
+;;   (funcall #'(,(monoid/classify)/empty)))
+;; (defun monoid/concat (xs)
+;;   "Sketch."
+;;   (apply #'(,(monoid/classify)/concat) args))
+
+
+(provide 'polymorphism)
+;;; polymorphism.el ends here
diff --git a/emacs/.emacs.d/wpc/prelude.el b/emacs/.emacs.d/wpc/prelude.el
new file mode 100644
index 000000000000..6ef9e3ba7afb
--- /dev/null
+++ b/emacs/.emacs.d/wpc/prelude.el
@@ -0,0 +1,149 @@
+;;; prelude.el --- My attempt at augmenting Elisp stdlib -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Some of these ideas are scattered across other modules like `fs',
+;; `string-functions', etc.  I'd like to keep everything modular.  I still don't
+;; have an answer for which items belond in `misc'; I don't want that to become
+;; a dumping grounds.  Ideally this file will `require' all other modules and
+;; define just a handful of functions.
+
+;; TODO: Consider removing all dependencies from prelude.el.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Third-party libraries
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 's)
+(require 'dash)
+(require 'f)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Libraries
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Maybe don't globally import everything here.  Disable these and attepmt
+;; to reload Emacs to assess damage.
+(require 'string)
+(require 'list)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Utilities
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun prelude/to-string (x)
+  "Convert X to a string."
+  (format "%s" x))
+
+(defun prelude/inspect (&rest args)
+  "Message `ARGS' where ARGS are any type."
+  (->> args
+       (list/map #'prelude/to-string)
+       (apply #'string/concat)
+       message))
+
+(defmacro prelude/call-process-to-string (cmd &rest args)
+  "Return the string output of CMD called with ARGS."
+  `(with-temp-buffer
+     (call-process ,cmd nil (current-buffer) nil ,@args)
+     (buffer-string)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Assertions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Should I `throw' instead of `error' here?
+(defmacro prelude/assert (x)
+  "Errors unless X is t.
+These are strict assertions and purposely do not rely on truthiness."
+  (let ((as-string (prelude/to-string x)))
+    `(unless (equal t ,x)
+       (error (string/concat "Assertion failed: " ,as-string)))))
+
+(defmacro prelude/refute (x)
+  "Errors unless X is nil."
+  (let ((as-string (prelude/to-string x)))
+    `(unless (equal nil ,x)
+       (error (string/concat "Refutation failed: " ,as-string)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Adapter functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun prelude/identity (x)
+  "Return X unchanged."
+  x)
+
+(defun prelude/const (x)
+  "Return a variadic lambda that will return X."
+  (lambda (&rest _) x))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Miscellaneous
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Consider packaging these into a linum-color.el package.
+;; TODO: Generate the color used here from the theme.
+(defvar linum/safe? nil
+  "Flag indicating whether or not it is safe to work with `linum-mode'.")
+
+(defvar linum/mru-color nil
+  "Stores the color most recently attempted to be applied.")
+
+(add-hook 'linum-mode-hook
+          (lambda ()
+            (setq linum/safe? t)
+            (when (maybe/some? linum/mru-color)
+              (set-face-foreground 'linum linum/mru-color))))
+
+(defun prelude/set-line-number-color (color)
+  "Safely set linum color to `COLOR'.
+
+If this is called before Emacs initializes, the color will be stored in
+`linum/mru-color' and applied once initialization completes.
+
+Why is this safe?
+If `(set-face-foreground 'linum)' is called before initialization completes,
+Emacs will silently fail.  Without this function, it is easy to introduce
+difficult to troubleshoot bugs in your init files."
+  (if linum/safe?
+      (set-face-foreground 'linum color)
+    (setq linum/mru-color color)))
+
+(defun prelude/prompt (prompt)
+  "Read input from user with PROMPT."
+  (read-string prompt))
+
+(cl-defun prelude/start-process (&key name command)
+  "Pass command string, COMMAND, and the function name, NAME.
+This is a wrapper around `start-process' that has an API that resembles
+`shell-command'."
+  ;; TODO: Fix the bug with tokenizing here, since it will split any whitespace
+  ;; character, even though it shouldn't in the case of quoted string in shell.
+  ;; e.g. - "xmodmap -e 'one two three'" => '("xmodmap" "-e" "'one two three'")
+  (prelude/refute (string/contains? "'" command))
+  (let* ((tokens (string/split " " command))
+         (program-name (list/head tokens))
+         (program-args (list/tail tokens)))
+    (apply #'start-process
+           `(,(string/format "*%s<%s>*" program-name name)
+             ,nil
+             ,program-name
+             ,@program-args))))
+
+(defun prelude/executable-exists? (name)
+  "Return t if CLI tool NAME exists according to `exec-path'."
+  (let ((file (locate-file name exec-path)))
+    (require 'maybe)
+    (if (maybe/some? file)
+        (f-exists? file)
+      nil)))
+
+(defmacro prelude/time (x)
+  "Print the time it takes to evaluate X."
+  `(benchmark 1 ',x))
+
+(provide 'prelude)
+;;; prelude.el ends here
diff --git a/emacs/.emacs.d/wpc/prelude.nix b/emacs/.emacs.d/wpc/prelude.nix
new file mode 100644
index 000000000000..626d4526a25d
--- /dev/null
+++ b/emacs/.emacs.d/wpc/prelude.nix
@@ -0,0 +1,11 @@
+{ pkgs ? import (builtins.fetchTarball
+  "https://github.com/tazjin/depot/archive/master.tar.gz") {} }:
+
+# Ciruclar dependency warning: list.nix depends on prelude.nix, which depends on
+# list.nix.
+pkgs.writeElispBin {
+  name = "prelude";
+  # If this can build with epkgs.ht, remove `(require 'ht)`.
+  deps = epkgs: [ epkgs.s epkgs.dash epkgs.f ./string.nix ./list.nix ];
+  src = ./prelude.el;
+}
diff --git a/emacs/.emacs.d/wpc/pulse-audio.el b/emacs/.emacs.d/wpc/pulse-audio.el
new file mode 100644
index 000000000000..dba4151a9e3d
--- /dev/null
+++ b/emacs/.emacs.d/wpc/pulse-audio.el
@@ -0,0 +1,66 @@
+;;; pulse-audio.el --- Control audio with Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Because everything in my configuration is turning into Elisp these days.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'string)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst pulse-audio/step-size 5
+  "The size by which to increase or decrease the volume.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun pulse-audio/message (x)
+  "Output X to *Messages*."
+  (message (string/format "[pulse-audio.el] %s" x)))
+
+(defun pulse-audio/toggle-mute ()
+  "Mute the default sink."
+  (interactive)
+  (prelude/start-process
+   :name "pulse-audio/toggle-mute"
+   :command "pactl set-sink-mute @DEFAULT_SINK@ toggle")
+  (pulse-audio/message "Mute toggled."))
+
+(defun pulse-audio/toggle-microphone ()
+  "Mute the default sink."
+  (interactive)
+  (prelude/start-process
+   :name "pulse-audio/toggle-microphone"
+   :command "pactl set-source-mute @DEFAULT_SOURCE@ toggle")
+  (pulse-audio/message "Microphone toggled."))
+
+(defun pulse-audio/decrease-volume ()
+  "Low the volume output of the default sink."
+  (interactive)
+  (prelude/start-process
+   :name "pulse-audio/decrease-volume"
+   :command (string/format "pactl set-sink-volume @DEFAULT_SINK@ -%s%%"
+                           pulse-audio/step-size))
+  (pulse-audio/message "Volume decreased."))
+
+(defun pulse-audio/increase-volume ()
+  "Raise the volume output of the default sink."
+  (interactive)
+  (prelude/start-process
+   :name "pulse-audio/increase-volume"
+   :command (string/format "pactl set-sink-volume @DEFAULT_SINK@ +%s%%"
+                           pulse-audio/step-size))
+  (pulse-audio/message "Volume increased."))
+
+(provide 'pulse-audio)
+;;; pulse-audio.el ends here
diff --git a/emacs/.emacs.d/wpc/pushover.el b/emacs/.emacs.d/wpc/pushover.el
new file mode 100644
index 000000000000..fb06656cf467
--- /dev/null
+++ b/emacs/.emacs.d/wpc/pushover.el
@@ -0,0 +1,75 @@
+;;; pushover.el --- Send generic messages to mobile device -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Pushover.net is a mobile app that accepts JSON.  This supports loose
+;; integration between things and mobile devices.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'request)
+(require 'password-store)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst pushover/app-token
+  (password-store-get-field "api-keys/pushover.net" "emacs")
+  "App token for \"emacs\" application.")
+
+(defconst pushover/user-key
+  (password-store-get "api-keys/pushover.net")
+  "Key that identifies me to pushover.")
+
+(defconst pushover/url
+  "https://api.pushover.net/1/messages.json"
+  "URL to POST messages.")
+
+;; TODO: Rename module "pushover".
+
+(defun pushover/notify (message)
+  "Posts MESSAGE to all devices.
+Here are the parameters that Pushover accepts:
+
+Required parameters:
+  - token - your application's API token
+  - user - the user/group key (not e-mail address) of your user (or you),
+    viewable when logged into our dashboard (often referred to as USER_KEY in
+    our documentation and code examples)
+  - message - your message
+
+Additional parameters (optional):
+  - attachment - an image attachment to send with the message; see attachments
+    for more information on how to upload files
+    device - your user's device name to send the message directly to that
+    device, rather than all of the user's devices (multiple devices may be
+    separated by a comma)
+  - title - your message's title, otherwise your app's name is used
+  - url - a supplementary URL to show with your message
+  - url_title - a title for your supplementary URL, otherwise just the URL is
+    shown
+  - priority - send as -2 to generate no notification/alert, -1 to always send
+    as a quiet notification, 1 to display as high-priority and bypass the user's
+    quiet hours, or 2 to also require confirmation from the user
+  - sound - the name of one of the sounds supported by device clients to
+    override the user's default sound choice
+  - timestamp - a Unix timestamp"
+  (request
+   pushover/url
+   :type "POST"
+   :params `(("token"   . ,pushover/app-token)
+             ("user"    . ,pushover/user-key)
+             ("message" . ,message))
+   :data nil
+   :parser 'json-read
+   :success (cl-function
+             (lambda (&key data &allow-other-keys)
+               (message "Pushover.net notification sent!")))))
+
+(provide 'pushover)
+;;; pushover.el ends here
diff --git a/emacs/.emacs.d/wpc/random.el b/emacs/.emacs.d/wpc/random.el
new file mode 100644
index 000000000000..148506c04d4e
--- /dev/null
+++ b/emacs/.emacs.d/wpc/random.el
@@ -0,0 +1,73 @@
+;;; random.el --- Functions for working with randomness -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Functions for working with randomness.  Some of this code is not as
+;; functional as I'd like from.
+
+;;; Code:
+
+(require 'prelude)
+(require 'number)
+(require 'math)
+(require 'series)
+(require 'list)
+(require 'set)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun random/int (x)
+  "Return a random integer from 0 to `X'."
+  (random x))
+
+;; TODO: Make this work with sequences instead of lists.
+(defun random/choice (xs)
+  "Return a random element of `XS'."
+  (let ((ct (list/length xs)))
+    (list/get
+     (random/int ct)
+     xs)))
+
+(defun random/boolean? ()
+  "Randonly return t or nil."
+  (random/choice (list t nil)))
+
+;; TODO: This may not work if any of these generate numbers like 0, 1, etc.
+(defun random/uuid ()
+  "Return a generated UUID string."
+  (let ((eight  (number/dec (math/triangle-of-power :base 16 :power 8)))
+        (four   (number/dec (math/triangle-of-power :base 16 :power 4)))
+        (twelve (number/dec (math/triangle-of-power :base 16 :power 12))))
+    (format "%x-%x-%x-%x-%x"
+            (random/int eight)
+            (random/int four)
+            (random/int four)
+            (random/int four)
+            (random/int twelve))))
+
+(defun random/token (length)
+  "Return a randomly generated hexadecimal string of LENGTH."
+  (->> (series/range 0 (number/dec length))
+       (list/map (lambda (_) (format "%x" (random/int 15))))
+       (list/join "")))
+
+;; TODO: Support random/sample
+(defun random/sample (n xs)
+  "Return a randomly sample of list XS of size N."
+  (prelude/assert (and (>= n 0) (< n (list/length xs))))
+  (cl-labels ((do-sample
+               (n xs y ys)
+               (if (= n (set/count ys))
+                   (->> ys
+                        set/to-list
+                        (list/map (lambda (i)
+                                    (list/get i xs))))
+                 (if (set/contains? y ys)
+                     (do-sample n xs (random/int (list/length xs)) ys)
+                   (do-sample n xs y (set/add y ys))))))
+    (do-sample n xs (random/int (list/length xs)) (set/new))))
+
+(provide 'random)
+;;; random.el ends here
diff --git a/emacs/.emacs.d/wpc/region.el b/emacs/.emacs.d/wpc/region.el
new file mode 100644
index 000000000000..a2119b4c96ce
--- /dev/null
+++ b/emacs/.emacs.d/wpc/region.el
@@ -0,0 +1,20 @@
+;;; region.el --- Functions for working with Emacs's regions -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Sometimes Emacs's function names and argument ordering is great; other times,
+;; it isn't.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun region/to-string ()
+  "Returns the string in the active region."
+  (buffer-substring-no-properties (region-beginning)
+                                  (region-end)))
+
+(provide 'region)
+;;; region.el ends here
diff --git a/emacs/.emacs.d/wpc/scheduler.el b/emacs/.emacs.d/wpc/scheduler.el
new file mode 100644
index 000000000000..bae953228925
--- /dev/null
+++ b/emacs/.emacs.d/wpc/scheduler.el
@@ -0,0 +1,22 @@
+;;; scheduler.el --- Sketches of scheduling -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Attempting to create a FSM for scheduling things in various ways:
+;;
+;; Scheduling policies:
+;; - earliest due date: minimizes total lateness of all tasks in a pool.  Put
+;;   the task with the latest due date last in the list and work backwards to
+;;   solve the precedence constraint (i.e. dependency issue).
+;; - shortest processing time: maximizes number of tasks completed.  Prioritize
+;;   tasks in the order of how long they will take to complete from shortest to
+;;   longest.  This breaks down when precedence constraints are introduced.
+;;
+;; Tasks should inherit prioritization.
+
+
+
+;;; Code:
+
+(provide 'scheduler)
+;;; scheduler.el ends here
diff --git a/emacs/.emacs.d/wpc/scope.el b/emacs/.emacs.d/wpc/scope.el
new file mode 100644
index 000000000000..48aa85ad0e5d
--- /dev/null
+++ b/emacs/.emacs.d/wpc/scope.el
@@ -0,0 +1,99 @@
+;;; scope.el --- Work with a scope data structure -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Exposing an API for working with a scope data structure in a non-mutative
+;; way.
+;;
+;; What's a scope?  Think of a scope as a stack of key-value bindings.
+
+;;; Code:
+
+(require 'alist)
+(require 'stack)
+(require 'struct)
+(require 'macros)
+
+(cl-defstruct scope scopes)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Create
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun scope/new ()
+  "Return an empty scope."
+  (make-scope :scopes (->> (stack/new)
+                           (stack/push (alist/new)))))
+
+(defun scope/flatten (xs)
+  "Return a flattened representation of the scope, XS.
+The newest bindings eclipse the oldest."
+  (->> xs
+       scope-scopes
+       stack/to-list
+       (list/reduce (alist/new)
+                    (lambda (scope acc)
+                      (alist/merge acc scope)))))
+
+(defun scope/push-new (xs)
+  "Push a new, empty scope onto XS."
+  (struct/update scope
+                 scopes
+                 (>> (stack/push (alist/new)))
+                 xs))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Read
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun scope/get (k xs)
+  "Return K from XS if it's in scope."
+  (->> xs
+       scope/flatten
+       (alist/get k)))
+
+(defun scope/current (xs)
+  "Return the newest scope from XS."
+  (let ((xs-copy (copy-scope xs)))
+    (->> xs-copy
+         scope-scopes
+         stack/peek)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Update
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun scope/set (k v xs)
+  "Set value, V, at key, K, in XS for the current scope."
+  (struct/update scope
+                 scopes
+                 (>> (stack/map-top (>> (alist/set k v))))
+                 xs))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Delete
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun scope/pop (xs)
+  "Return a new scope without the top element from XS."
+  (->> xs
+       scope-scopes
+       stack/pop))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun scope/defined? (k xs)
+  "Return t if K is in scope of XS."
+  (->> xs
+       scope/flatten
+       (alist/has-key? k)))
+
+;; TODO: Find a faster way to write aliases like this.
+(defun scope/instance? (xs)
+  "Return t if XS is a scope struct."
+  (scope-p xs))
+
+(provide 'scope)
+;;; scope.el ends here
diff --git a/emacs/.emacs.d/wpc/screen-brightness.el b/emacs/.emacs.d/wpc/screen-brightness.el
new file mode 100644
index 000000000000..ad51e7578cca
--- /dev/null
+++ b/emacs/.emacs.d/wpc/screen-brightness.el
@@ -0,0 +1,45 @@
+;;; screen-brightness.el --- Control laptop screen brightness -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Mainly just Elisp wrappers around `xbacklight`.
+
+;;; Code:
+
+;; TODO: Define some isomorphisms. E.g. int->string, string->int.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Constants
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst screen-brightness/step-size 15
+  "The size of the increment or decrement step for the screen's brightness.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun screen-brightness/increase ()
+  "Increase the screen brightness."
+  (interactive)
+  (prelude/start-process
+   :name "screen-brightness/increase"
+   :command (string/format "xbacklight -inc %s" screen-brightness/step-size))
+  (message "[screen-brightness.el] Increased screen brightness."))
+
+(defun screen-brightness/decrease ()
+  "Decrease the screen brightness."
+  (interactive)
+  (prelude/start-process
+   :name "screen-brightness/decrease"
+   :command (string/format "xbacklight -dec %s" screen-brightness/step-size))
+  (message "[screen-brightness.el] Decreased screen brightness."))
+
+(provide 'screen-brightness)
+;;; screen-brightness.el ends here
diff --git a/emacs/.emacs.d/wpc/scrot.el b/emacs/.emacs.d/wpc/scrot.el
new file mode 100644
index 000000000000..eeb12b3731e9
--- /dev/null
+++ b/emacs/.emacs.d/wpc/scrot.el
@@ -0,0 +1,64 @@
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; scrot is a Linux utility for taking screenshots.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'f)
+(require 'string)
+(require 'ts)
+(require 'clipboard)
+(require 'kbd)
+
+(prelude/assert
+ (prelude/executable-exists? "scrot"))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst scrot/screenshot-directory "~/Downloads"
+  "The default directory for screenshot outputs.")
+
+(defconst scrot/path-to-executable "/usr/bin/scrot"
+  "Path to the scrot executable.")
+
+(defconst scrot/output-format "screenshot_%H:%M:%S_%Y-%m-%d.png"
+  "The format string for the output screenshot file.
+See scrot's man page for more information.")
+
+(defun scrot/copy-image (path)
+  "Use xclip to copy the image at PATH to the clipboard.
+This currently only works for PNG files because that's what I'm outputting"
+  (call-process "xclip" nil nil nil
+                "-selection" "clipboard" "-t" "image/png" path)
+  (message (string/format "[scrot.el] Image copied to clipboard!")))
+
+(defmacro scrot/call (&rest args)
+  "Call scrot with ARGS."
+  `(call-process ,scrot/path-to-executable nil nil nil ,@args))
+
+(defun scrot/fullscreen ()
+  "Screenshot the entire screen."
+  (interactive)
+  (let ((screenshot-path (f-join scrot/screenshot-directory
+                                 (ts-format scrot/output-format (ts-now)))))
+    (scrot/call screenshot-path)
+    (scrot/copy-image screenshot-path)))
+
+(defun scrot/select ()
+  "Click-and-drag to screenshot a region.
+The output path is copied to the user's clipboard."
+  (interactive)
+  (let ((screenshot-path (f-join scrot/screenshot-directory
+                                 (ts-format scrot/output-format (ts-now)))))
+    (scrot/call "--select" screenshot-path)
+    (scrot/copy-image screenshot-path)))
+
+(provide 'scrot)
+;;; scrot.el ends here
diff --git a/emacs/.emacs.d/wpc/sequence.el b/emacs/.emacs.d/wpc/sequence.el
new file mode 100644
index 000000000000..a5428ef04448
--- /dev/null
+++ b/emacs/.emacs.d/wpc/sequence.el
@@ -0,0 +1,105 @@
+;;; sequence.el --- Working with the "sequence" types -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Elisp supports a typeclass none as "sequence" which covers the following
+;; types:
+;; - list: '(1 2 3 4 5)
+;; - vector: ["John" 27 :blue]
+;; - string: "To be or not to be..."
+
+;; TODO: Document the difference between a "reduce" and a "fold".  I.e. - reduce
+;; has an initial value whereas fold uses the first element in the sequence as
+;; the initial value.
+;;
+;; Note: This should be an approximation of Elixir's Enum protocol albeit
+;; without streams.
+;;
+;; Elisp has done a lot of this work already and these are mostly wrapper
+;; functions.
+;; See the following list for reference:
+;; - sequencep
+;; - elt
+;; - copy-sequence
+;; - reverse
+;; - nreverse
+;; - sort
+;; - seq-elt
+;; - seq-length
+;; - seqp
+;; - seq-drop
+;; - seq-take
+;; - seq-take-while
+;; - seq-drop-while
+;; - seq-do
+;; - seq-map
+;; - seq-mapn
+;; - seq-filter
+;; - seq-remove
+;; - seq-reduce
+;; - seq-some
+;; - seq-find
+;; - seq-every-p
+;; - seq-empty-p
+;; - seq-count
+;; - seq-sort
+;; - seq-contains
+;; - seq-position
+;; - seq-uniq
+;; - seq-subseq
+;; - seq-concatenate
+;; - seq-mapcat
+;; - seq-partition
+;; - seq-intersection
+;; - seq-difference
+;; - seq-group-by
+;; - seq-into
+;; - seq-min
+;; - seq-max
+;; - seq-doseq
+;; - seq-let
+
+;;; Code:
+
+;; Perhaps we can provide default implementations for `filter' and `map' derived
+;; from the `reduce' implementation.
+;; (defprotocol sequence
+;;   :functions (reduce))
+;; (definstance sequence list
+;;   :reduce #'list/reduce
+;;   :filter #'list/filter
+;;   :map    #'list/map)
+;; (definstance sequence vector
+;;   :reduce #'vector/reduce)
+;; (definstance sequence string
+;;   :reduce #'string)
+
+(defun sequence/classify (xs)
+  "Return the type of `XS'."
+  (cond
+   ((listp xs) 'list)
+   ((vectorp xs) 'vector)
+   ((stringp xs) 'string)))
+
+(defun sequence/reduce (acc f xs)
+  "Reduce of `XS' calling `F' on x and `ACC'."
+  (seq-reduce
+   (lambda (acc x)
+     (funcall f x acc))
+   xs
+   acc))
+
+;; Elixir also turned everything into a list for efficiecy reasons.
+
+(defun sequence/filter (p xs)
+  "Filter `XS' with predicate, `P'.
+Returns a list regardless of the type of `XS'."
+  (seq-filter p xs))
+
+(defun sequence/map (f xs)
+  "Maps `XS' calling `F' on each element.
+Returns a list regardless of the type of `XS'."
+  (seq-map f xs))
+
+(provide 'sequence)
+;;; sequence.el ends here
diff --git a/emacs/.emacs.d/wpc/series.el b/emacs/.emacs.d/wpc/series.el
new file mode 100644
index 000000000000..55e97f278984
--- /dev/null
+++ b/emacs/.emacs.d/wpc/series.el
@@ -0,0 +1,89 @@
+;;; series.el --- Hosting common series of numbers -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Encoding number series as I learn about them.
+;;
+;; These are the following series I'm interested in supporting:
+;; - Fibonacci
+;; - Catalan numbers
+;; - Figurate number series
+;;   - Triangular
+;;   - Square
+;;   - Pentagonal
+;;   - Hexagonal
+;;   - Lazy-caterer
+;; - Magic square
+;; - Look-and-say
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'number)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun series/range (beg end)
+  "Create a list of numbers from `BEG' to `END'.
+This is an inclusive number range."
+  (if (< end beg)
+      (list/reverse
+       (number-sequence end beg))
+    (number-sequence beg end)))
+
+(defun series/fibonacci-number (i)
+  "Return the number in the fibonacci series at `I'."
+  (cond
+   ((= 0 i) 0)
+   ((= 1 i) 1)
+   (t (+ (series/fibonacci-number (- i 1))
+         (series/fibonacci-number (- i 2))))))
+
+(defun series/fibonacci (n)
+  "Return the first `N' numbers of the fibonaccci series starting at zero."
+  (if (= 0 n)
+      '()
+    (list/reverse
+     (list/cons (series/fibonacci-number (number/dec n))
+                (list/reverse
+                 (series/fibonacci (number/dec n)))))))
+
+;; TODO: Consider memoization.
+(defun series/triangular-number (i)
+  "Return the number in the triangular series at `I'."
+  (if (= 0 i)
+      0
+    (+ i (series/triangular-number (number/dec i)))))
+
+;; TODO: Improve performance.
+;; TODO: Consider creating a stream protocol with `stream/next' and implement
+;; this using that.
+(defun series/triangular (n)
+  "Return the first `N' numbers of a triangular series starting at 0."
+  (if (= 0 n)
+      '()
+    (list/reverse
+     (list/cons (series/triangular-number (number/dec n))
+                (list/reverse
+                 (series/triangular (number/dec n)))))))
+
+(defun series/catalan-number (i)
+  "Return the catalan number in the series at `I'."
+  (if (= 0 i)
+      1
+    (/ (number/factorial (* 2 i))
+       (* (number/factorial (number/inc i))
+          (number/factorial i)))))
+
+(defun series/catalan (n)
+  "Return the first `N' numbers in a catalan series."
+  (->> (series/range 0 (number/dec n))
+       (list/map #'series/catalan-number)))
+
+(provide 'series)
+;;; series.el ends here
diff --git a/emacs/.emacs.d/wpc/set.el b/emacs/.emacs.d/wpc/set.el
new file mode 100644
index 000000000000..ff2db75d94ab
--- /dev/null
+++ b/emacs/.emacs.d/wpc/set.el
@@ -0,0 +1,171 @@
+;;; set.el --- Working with mathematical sets -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; The set data structure is a collection that deduplicates its elements.
+
+;;; Code:
+
+(require 'ht) ;; friendlier API for hash-tables
+(require 'dotted)
+(require 'struct)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Wish List
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; - TODO: Support enum protocol for set.
+;; - TODO: Prefer a different hash-table library that doesn't rely on mutative
+;;   code.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defstruct set xs)
+
+(defconst set/enable-testing? t
+  "Run tests when t.")
+
+(defun set/from-list (xs)
+  "Create a new set from the list XS."
+  (make-set :xs (->> xs
+                     (list/map #'dotted/new)
+                     ht-from-alist)))
+
+(defun set/new (&rest args)
+  "Create a new set from ARGS."
+  (set/from-list args))
+
+(defun set/to-list (xs)
+  "Map set XS into a list."
+  (->> xs
+       set-xs
+       ht-keys))
+
+(defun set/add (x xs)
+  "Add X to set XS."
+  (struct/update set
+                 xs
+                 (lambda (table)
+                   (let ((table-copy (ht-copy table)))
+                     (ht-set table-copy x nil)
+                     table-copy))
+                 xs))
+
+;; TODO: Ensure all `*/reduce' functions share the same API.
+(defun set/reduce (acc f xs)
+  "Return a new set by calling F on each element of XS and ACC."
+  (->> xs
+       set/to-list
+       (list/reduce acc f)))
+
+(defun set/intersection (a b)
+  "Return the set intersection between sets A and B."
+  (set/reduce (set/new)
+              (lambda (x acc)
+                (if (set/contains? x b)
+                    (set/add x acc)
+                  acc))
+              a))
+
+(defun set/count (xs)
+  "Return the number of elements in XS."
+  (->> xs
+       set-xs
+       ht-size))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun set/empty? (xs)
+  "Return t if XS has no elements in it."
+  (= 0 (set/count xs)))
+
+(defun set/contains? (x xs)
+  "Return t if set XS has X."
+  (ht-contains? (set-xs xs) x))
+
+;; TODO: Prefer using `ht.el' functions for this.
+(defun set/equal? (a b)
+  "Return t if A and B share the name members."
+  (ht-equal? (set-xs a)
+             (set-xs b)))
+
+(defun set/distinct? (a b)
+  "Return t if sets A and B have no shared members."
+  (set/empty? (set/intersection a b)))
+
+(defun set/superset? (a b)
+  "Return t if set A contains all of the members of set B."
+  (->> b
+       set/to-list
+       (list/all? (lambda (x) (set/contains? x a)))))
+
+(defun set/subset? (a b)
+  "Return t if each member of set A is present in set B."
+  (set/superset? b a))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when set/enable-testing?
+  ;; set/distinct?
+  (prelude/assert
+   (set/distinct? (set/new 'one 'two 'three)
+                  (set/new 'a 'b 'c)))
+  (prelude/refute
+   (set/distinct? (set/new 1 2 3)
+                  (set/new 3 4 5)))
+  (prelude/refute
+   (set/distinct? (set/new 1 2 3)
+                  (set/new 1 2 3)))
+  ;; set/equal?
+  (prelude/refute
+   (set/equal? (set/new 'a 'b 'c)
+               (set/new 'x 'y 'z)))
+  (prelude/refute
+   (set/equal? (set/new 'a 'b 'c)
+               (set/new 'a 'b)))
+  (prelude/assert
+   (set/equal? (set/new 'a 'b 'c)
+               (set/new 'a 'b 'c)))
+  ;; set/intersection
+  (prelude/assert
+   (set/equal? (set/new 2 3)
+               (set/intersection (set/new 1 2 3)
+                                 (set/new 2 3 4))))
+  ;; set/{from,to}-list
+  (prelude/assert (equal '(1 2 3)
+                         (->> '(1 1 2 2 3 3)
+                              set/from-list
+                              set/to-list)))
+  (let ((primary-colors (set/new "red" "green" "blue")))
+    ;; set/subset?
+    (prelude/refute
+     (set/subset? (set/new "black" "grey")
+                  primary-colors))
+    (prelude/assert
+     (set/subset? (set/new "red")
+                  primary-colors))
+    ;; set/superset?
+    (prelude/refute
+     (set/superset? primary-colors
+                    (set/new "black" "grey")))
+    (prelude/assert
+     (set/superset? primary-colors
+                    (set/new "red" "green" "blue")))
+    (prelude/assert
+     (set/superset? primary-colors
+                    (set/new "red" "blue"))))
+  ;; set/empty?
+  (prelude/assert (set/empty? (set/new)))
+  (prelude/refute (set/empty? (set/new 1 2 3)))
+  ;; set/count
+  (prelude/assert (= 0 (set/count (set/new))))
+  (prelude/assert (= 2 (set/count (set/new 1 1 2 2)))))
+
+(provide 'set)
+;;; set.el ends here
diff --git a/emacs/.emacs.d/wpc/ssh.el b/emacs/.emacs.d/wpc/ssh.el
new file mode 100644
index 000000000000..d7039375731e
--- /dev/null
+++ b/emacs/.emacs.d/wpc/ssh.el
@@ -0,0 +1,31 @@
+;;; ssh.el --- When working remotely -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Configuration to make remote work easier.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'tramp)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Is "ssh" preferable to "scp"?
+(setq tramp-default-method "ssh")
+
+;; Taken from: https://superuser.com/questions/179313/tramp-waiting-for-prompts-from-remote-shell
+(setq tramp-shell-prompt-pattern "^[^$>\n]*[#$%>] *\\(\[[0-9;]*[a-zA-Z] *\\)*")
+
+;; TODO: Re-enable this in case "dumb" isn't the default.
+;; (setq tramp-terminal-type "dumb")
+
+(setq tramp-verbose 10)
+
+(provide 'ssh)
+;;; ssh.el ends here
diff --git a/emacs/.emacs.d/wpc/stack.el b/emacs/.emacs.d/wpc/stack.el
new file mode 100644
index 000000000000..052ed881d20f
--- /dev/null
+++ b/emacs/.emacs.d/wpc/stack.el
@@ -0,0 +1,93 @@
+;;; stack.el --- Working with stacks in Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; A stack is a LIFO queue.
+;; The design goal here is to expose an intuitive API for working with stacks in
+;; non-mutative way.
+;;
+;; TODO: Consider naming a Functor instance "Mappable."
+;; TODO: Consider naming a Foldable instance "Reduceable."
+;;
+;; TODO: Consider implementing an instance for Mappable.
+;; TODO: Consider implementing an instance for Reduceable.
+
+;;; Code:
+
+(require 'list)
+
+(cl-defstruct stack xs)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Create
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun stack/new ()
+  "Create an empty stack."
+  (make-stack :xs '()))
+
+(defun stack/from-list (xs)
+  "Create a new stack from the list, `XS'."
+  (list/reduce (stack/new) #'stack/push xs))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Read
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun stack/peek (xs)
+  "Look at the top element of `XS' without popping it off."
+  (->> xs
+       stack-xs
+       list/head))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Update
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun stack/push (x xs)
+  "Push `X' on `XS'."
+  (struct/update stack
+                 xs
+                 (>> (list/cons x))
+                 xs))
+
+;; TODO: How to return something like {(list/head xs), (list/tail xs)} in Elixir
+;; TODO: How to handle popping from empty stacks?
+(defun stack/pop (xs)
+  "Return the stack, `XS', without the top element.
+Since I cannot figure out a nice way of return tuples in Elisp, if you want to
+look at the first element, use `stack/peek' before running `stack/pop'."
+  (struct/update stack
+                 xs
+                 (>> list/tail)
+                 xs))
+
+(defun stack/map-top (f xs)
+  "Apply F to the top element of XS."
+  (->> xs
+       stack/pop
+       (stack/push (funcall f (stack/peek xs)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Miscellaneous
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun stack/to-list (xs)
+  "Return XS as a list.
+The round-trip property of `stack/from-list' and `stack/to-list' should hold."
+  (->> xs
+       stack-xs
+       list/reverse))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Create a macro that wraps `cl-defstruct' that automatically creates
+;; things like `new', `instance?'.
+(defun stack/instance? (xs)
+  "Return t if XS is a stack."
+  (stack-p xs))
+
+(provide 'stack)
+;;; stack.el ends here
diff --git a/emacs/.emacs.d/wpc/string.el b/emacs/.emacs.d/wpc/string.el
new file mode 100644
index 000000000000..f8694d5f18a1
--- /dev/null
+++ b/emacs/.emacs.d/wpc/string.el
@@ -0,0 +1,128 @@
+;; string.el --- Library for working with strings -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Library for working with string.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 's)
+(require 'dash)
+;; TODO: Resolve the circular dependency that this introduces.
+;; (require 'prelude)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst string/test? t
+  "When t, run the tests.")
+
+(defun string/contains? (c x)
+  "Return t if X is in C."
+  (s-contains? c x))
+
+(defun string/hookify (x)
+  "Append \"-hook\" to X."
+  (s-append "-hook" x))
+
+(defun string/split (y x)
+  "Map string X into a list of strings that were separated by Y."
+  (s-split y x))
+
+(defun string/ensure-hookified (x)
+  "Ensure that X has \"-hook\" appended to it."
+  (if (s-ends-with? "-hook" x)
+      x
+    (string/hookify x)))
+
+(defun string/format (x &rest args)
+  "Format template string X with ARGS."
+  (apply #'format (cons x args)))
+
+(defun string/concat (&rest strings)
+  "Joins `STRINGS' into onto string."
+  (apply #'s-concat strings))
+
+(defun string/->symbol (string)
+  "Maps `STRING' to a symbol."
+  (intern string))
+
+(defun string/<-symbol (symbol)
+  "Maps `SYMBOL' into a string."
+  (symbol-name symbol))
+
+(defun string/prepend (prefix x)
+  "Prepend `PREFIX' onto `X'."
+  (s-concat prefix x))
+
+(defun string/append (postfix x)
+  "Appen `POSTFIX' onto `X'."
+  (s-concat x postfix))
+
+(defun string/surround (s x)
+  "Surrounds `X' one each side with `S'."
+  (->> x
+       (string/prepend s)
+       (string/append s)))
+
+;; TODO: Define a macro for defining a function and a test.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Casing
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun string/caps->kebab (x)
+  "Change the casing of `X' from CAP_CASE to kebab-case."
+  (->> x
+       s-downcase
+       (s-replace "_" "-")))
+
+(defun string/kebab->caps (x)
+  "Change the casing of X from CAP_CASE to kebab-case."
+  (->> x
+       s-upcase
+       (s-replace "-" "_")))
+
+(defun string/lower->caps (x)
+  "Change the casing of X from lowercase to CAPS_CASE."
+  (->> x
+       s-upcase
+       (s-replace " " "_")))
+
+(defun string/lower->kebab (x)
+  "Change the casing of `X' from lowercase to kebab-case."
+  (s-replace " " "-" x))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun string/instance? (x)
+  "Return t if X is a string."
+  (stringp x))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; (when string/test?
+;;   (prelude/assert
+;;    (string=
+;;     (string/surround "-*-" "surround")
+;;     "-*-surround-*-"))
+;;   (prelude/assert
+;;    (string=
+;;     (string/caps->kebab "CAPS_CASE_STRING")
+;;     "caps-case-string"))
+;;   (prelude/assert
+;;    (string=
+;;     (string/kebab->caps "kebab-case-string")
+;;     "KEBAB_CASE_STRING")))
+
+(provide 'string)
+;;; string.el ends here
diff --git a/emacs/.emacs.d/wpc/string.nix b/emacs/.emacs.d/wpc/string.nix
new file mode 100644
index 000000000000..1f815b26bb37
--- /dev/null
+++ b/emacs/.emacs.d/wpc/string.nix
@@ -0,0 +1,8 @@
+{ pkgs ? import (builtins.fetchTarball
+  "https://github.com/tazjin/depot/archive/master.tar.gz") {} }:
+
+pkgs.writeElispBin {
+  name = "string";
+  deps = epkgs: [ epkgs.dash epkgs.s ./prelude.nix ];
+  src = ./string.el;
+}
diff --git a/emacs/.emacs.d/wpc/struct.el b/emacs/.emacs.d/wpc/struct.el
new file mode 100644
index 000000000000..7d237d3259ff
--- /dev/null
+++ b/emacs/.emacs.d/wpc/struct.el
@@ -0,0 +1,88 @@
+;;; struct.el --- Helpers for working with structs -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Provides new macros for working with structs.  Also provides adapter
+;; interfaces to existing struct macros, that should have more intuitive
+;; interfaces.
+;;
+;; Sometimes `setf' just isn't enough.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Wish list
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; - TODO: Replace `symbol-name' and `intern' calls with isomorphism.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'string)
+(require 'dash)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar struct/enable-tests? t
+  "When t, run the test suite defined herein.")
+
+(defmacro struct/update (type field f xs)
+  "Apply F to FIELD in XS, which is a struct of TYPE.
+This is immutable."
+  (let ((copier (->> type
+                     symbol-name
+                     (string/prepend "copy-")
+                     intern))
+        (accessor (->> field
+                       symbol-name
+                       (string/prepend (string/concat (symbol-name type) "-"))
+                       intern)))
+    `(let ((copy (,copier ,xs)))
+       (setf (,accessor copy) (funcall ,f (,accessor copy)))
+       copy)))
+
+(defmacro struct/set (type field x xs)
+  "Immutably set FIELD in XS (struct TYPE) to X."
+  (let ((copier (->> type
+                     symbol-name
+                     (string/prepend "copy-")
+                     intern))
+        (accessor (->> field
+                       symbol-name
+                       (string/prepend (string/concat (symbol-name type) "-"))
+                       intern)))
+    `(let ((copy (,copier ,xs)))
+       (setf (,accessor copy) ,x)
+       copy)))
+
+(defmacro struct/set! (type field x xs)
+  "Set FIELD in XS (struct TYPE) to X mutably.
+This is an adapter interface to `setf'."
+  (let ((accessor (->> field
+                       symbol-name
+                       (string/prepend (string/concat (symbol-name type) "-"))
+                       intern)))
+    `(progn
+       (setf (,accessor ,xs) ,x)
+       ,xs)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when struct/enable-tests?
+  (cl-defstruct dummy name age)
+  (defvar test-dummy (make-dummy :name "Roofus" :age 19))
+  (struct/set! dummy name "Doofus" test-dummy)
+  (prelude/assert (string= "Doofus" (dummy-name test-dummy)))
+  (let ((result (struct/set dummy name "Shoofus" test-dummy)))
+    ;; Test the immutability of `struct/set'
+    (prelude/assert (string= "Doofus" (dummy-name test-dummy)))
+    (prelude/assert (string= "Shoofus" (dummy-name result)))))
+
+(provide 'struct)
+;;; struct.el ends here
diff --git a/emacs/.emacs.d/wpc/symbol.el b/emacs/.emacs.d/wpc/symbol.el
new file mode 100644
index 000000000000..9119b29470fd
--- /dev/null
+++ b/emacs/.emacs.d/wpc/symbol.el
@@ -0,0 +1,43 @@
+;; symbol.el --- Library for working with symbols. -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Library for working with symbols.
+
+;;; Code:
+
+;; TODO: Why is ivy mode map everywhere?
+
+(require 'string)
+
+;; Symbols
+(defun symbol/as-string (callback x)
+  "Treat the symbol, X, as a string while applying CALLBACK to it.
+Coerce back to a symbol on the way out."
+  (->> x
+       #'symbol-name
+       callback
+       #'intern))
+
+(defun symbol/to-string (x)
+  "Map `X' into a string."
+  (string/<-symbol x))
+
+(defun symbol/hookify (x)
+  "Append \"-hook\" to X when X is a symbol."
+  (symbol/as-string #'string/hookify x))
+
+(defun symbol/ensure-hookified (x)
+  "Ensure that X has \"-hook\" appended to it when X is a symbol."
+  (symbol/as-string #'string/ensure-hookified x))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun symbol/instance? (x)
+  "Return t if X is a symbol."
+  (symbolp x))
+
+(provide 'symbol)
+;;; symbol.el ends here
diff --git a/emacs/.emacs.d/wpc/terminator-themes.json b/emacs/.emacs.d/wpc/terminator-themes.json
new file mode 100644
index 000000000000..e021ef12932f
--- /dev/null
+++ b/emacs/.emacs.d/wpc/terminator-themes.json
@@ -0,0 +1,1794 @@
+{
+  "themes": [
+    {
+      "name": "3024 Day",
+      "palette": "#090300:#db2d20:#01a252:#fded02:#01a0e4:#a16a94:#b5e4f4:#a5a2a2:#5c5855:#e8bbd0:#3a3432:#4a4543:#807d7c:#d6d5d4:#cdab53:#f7f7f7",
+      "background_color": "#f7f7f7",
+      "cursor_color": "#4a4543",
+      "foreground_color": "#4a4543",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "3024 Night",
+      "palette": "#090300:#db2d20:#01a252:#fded02:#01a0e4:#a16a94:#b5e4f4:#a5a2a2:#5c5855:#e8bbd0:#3a3432:#4a4543:#807d7c:#d6d5d4:#cdab53:#f7f7f7",
+      "background_color": "#090300",
+      "cursor_color": "#a5a2a2",
+      "foreground_color": "#a5a2a2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Aci",
+      "background_color": "#0d1926",
+      "background_image": "None",
+      "cursor_color": "#c4e9ff",
+      "foreground_color": "#b4e1fd",
+      "palette": "#363636:#ff0883:#83ff08:#ff8308:#0883ff:#8308ff:#08ff83:#b6b6b6:#363636:#ff0883:#83ff08:#ff8308:#0883ff:#8308ff:#08ff83:#b6b6b6",
+      "type": "dark"
+    },
+    {
+      "name": "Aco",
+      "background_color": "#1f1305",
+      "background_image": "None",
+      "cursor_color": "#bae2fb",
+      "foreground_color": "#b4e1fd",
+      "palette": "#3f3f3f:#ff0883:#83ff08:#ff8308:#0883ff:#8308ff:#08ff83:#bebebe:#474747:#ff1e8e:#8eff1e:#ff8e1e:#0883ff:#8e1eff:#1eff8e:#c4c4c4",
+      "type": "dark"
+    },
+    {
+      "name": "AdventureTime",
+      "palette": "#050404:#bd0013:#4ab118:#e7741e:#0f4ac6:#665993:#70a598:#f8dcc0:#4e7cbf:#fc5f5a:#9eff6e:#efc11a:#1997c6:#9b5953:#c8faf4:#f6f5fb",
+      "background_color": "#1f1d45",
+      "cursor_color": "#efbf38",
+      "foreground_color": "#f8dcc0",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "After Dark",
+      "background_color": "#10111b",
+      "cursor_color": "#aaaaaa",
+      "palette": "#2e3436:#ef4a9e:#00d2bc:#e7ca7a:#9399fa:#ca5bcc:#86d079:#d3d7cf:#555753:#ef4a9e:#00d2bc:#e7ca7a:#9399fa:#ca5bcc:#86d079:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "Afterglow",
+      "palette": "#151515:#ac4142:#7e8e50:#e5b567:#6c99bb:#9f4e85:#7dd6cf:#d0d0d0:#505050:#ac4142:#7e8e50:#e5b567:#6c99bb:#9f4e85:#7dd6cf:#f5f5f5",
+      "background_color": "#212121",
+      "cursor_color": "#d0d0d0",
+      "foreground_color": "#d0d0d0",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "AlienBlood",
+      "palette": "#112616:#7f2b27:#2f7e25:#717f24:#2f6a7f:#47587f:#327f77:#647d75:#3c4812:#e08009:#18e000:#bde000:#00aae0:#0058e0:#00e0c4:#73fa91",
+      "background_color": "#0f1610",
+      "cursor_color": "#73fa91",
+      "foreground_color": "#637d75",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Argonaut",
+      "palette": "#232323:#ff000f:#8ce10b:#ffb900:#008df8:#6d43a6:#00d8eb:#ffffff:#444444:#ff2740:#abe15b:#ffd242:#0092ff:#9a5feb:#67fff0:#ffffff",
+      "background_color": "#0e1019",
+      "cursor_color": "#ff0018",
+      "foreground_color": "#fffaf4",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Arthur",
+      "palette": "#3d352a:#cd5c5c:#86af80:#e8ae5b:#6495ed:#deb887:#b0c4de:#bbaa99:#554444:#cc5533:#88aa22:#ffa75d:#87ceeb:#996600:#b0c4de:#ddccbb",
+      "background_color": "#1c1c1c",
+      "cursor_color": "#e2bbef",
+      "foreground_color": "#ddeedd",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "AtelierSulphurpool",
+      "palette": "#202746:#c94922:#ac9739:#c08b30:#3d8fd1:#6679cc:#22a2c9:#979db4:#6b7394:#c76b29:#293256:#5e6687:#898ea4:#dfe2f1:#9c637a:#f5f7ff",
+      "background_color": "#202746",
+      "cursor_color": "#979db4",
+      "foreground_color": "#979db4",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Atom",
+      "palette": "#000000:#fd5ff1:#87c38a:#ffd7b1:#85befd:#b9b6fc:#85befd:#e0e0e0:#000000:#fd5ff1:#94fa36:#f5ffa8:#96cbfe:#b9b6fc:#85befd:#e0e0e0",
+      "background_color": "#161719",
+      "cursor_color": "#d0d0d0",
+      "foreground_color": "#c5c8c6",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "AtomOneLight",
+      "palette": "#000000:#de3e35:#3f953a:#d2b67c:#2f5af3:#950095:#3f953a:#bbbbbb:#000000:#de3e35:#3f953a:#d2b67c:#2f5af3:#a00095:#3f953a:#ffffff",
+      "background_color": "#f9f9f9",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#2a2c33",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "ayu",
+      "palette": "#000000:#ff3333:#b8cc52:#e7c547:#36a3d9:#f07178:#95e6cb:#ffffff:#323232:#ff6565:#eafe84:#fff779:#68d5ff:#ffa3aa:#c7fffd:#ffffff",
+      "background_color": "#0f1419",
+      "cursor_color": "#f29718",
+      "foreground_color": "#e6e1cf",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Ayu mirage",
+      "background_color": "#212733",
+      "background_image": "None",
+      "cursor_color": "#FFD580",
+      "foreground_color": "#d9d7ce",
+      "palette": "#212733:#ff3333:#bae67e:#ffd580:#5ccfe6:#d4bfff:#5ccfe6:#3d4752:#3e4b59:#ff3333:#bae67e:#ffd580:#5ccfe6:#d4bfff:#5ccfe6:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "ayu_light",
+      "palette": "#000000:#ff3333:#86b300:#f29718:#41a6d9:#f07178:#4dbf99:#ffffff:#323232:#ff6565:#b8e532:#ffc94a:#73d8ff:#ffa3aa:#7ff1cb:#ffffff",
+      "background_color": "#fafafa",
+      "cursor_color": "#ff6a00",
+      "foreground_color": "#5c6773",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Azu",
+      "background_color": "#09111a",
+      "background_image": "None",
+      "cursor_color": "#d2e8fc",
+      "foreground_color": "#d9e6f2",
+      "palette": "#000000:#ac6d74:#74ac6d:#aca46d:#6d74ac:#a46dac:#6daca4:#e6e6e6:#262626:#d6b8bc:#bcd6b8:#d6d3b8:#b8bcd6:#d3b8d6:#b8d6d3:#ffffff",
+      "type": "dark"
+    },
+    {
+      "name": "Batman",
+      "palette": "#1b1d1e:#e6dc44:#c8be46:#f4fd22:#737174:#747271:#62605f:#c6c5bf:#505354:#fff78e:#fff27d:#feed6c:#919495:#9a9a9d:#a3a3a6:#dadbd6",
+      "background_color": "#1b1d1e",
+      "cursor_color": "#fcef0c",
+      "foreground_color": "#6f6f6f",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Belafonte Day",
+      "palette": "#20111b:#be100e:#858162:#eaa549:#426a79:#97522c:#989a9c:#968c83:#5e5252:#be100e:#858162:#eaa549:#426a79:#97522c:#989a9c:#d5ccba",
+      "background_color": "#d5ccba",
+      "cursor_color": "#45373c",
+      "foreground_color": "#45373c",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Belafonte Night",
+      "palette": "#20111b:#be100e:#858162:#eaa549:#426a79:#97522c:#989a9c:#968c83:#5e5252:#be100e:#858162:#eaa549:#426a79:#97522c:#989a9c:#d5ccba",
+      "background_color": "#20111b",
+      "cursor_color": "#968c83",
+      "foreground_color": "#968c83",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Bim",
+      "background_color": "#012849",
+      "background_image": "None",
+      "cursor_color": "#c4d0de",
+      "foreground_color": "#a9bed8",
+      "palette": "#2c2423:#f557a0:#a9ee55:#f5a255:#5ea2ec:#a957ec:#5eeea0:#918988:#918988:#f579b2:#bbee78:#f5b378:#81b3ec:#bb79ec:#81eeb2:#f5eeec",
+      "type": "dark"
+    },
+    {
+      "name": "BirdsOfParadise",
+      "palette": "#573d26:#be2d26:#6ba18a:#e99d2a:#5a86ad:#ac80a6:#74a6ad:#e0dbb7:#9b6c4a:#e84627:#95d8ba:#d0d150:#b8d3ed:#d19ecb:#93cfd7:#fff9d5",
+      "background_color": "#2a1f1d",
+      "cursor_color": "#573d26",
+      "foreground_color": "#e0dbb7",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Blazer",
+      "palette": "#000000:#b87a7a:#7ab87a:#b8b87a:#7a7ab8:#b87ab8:#7ab8b8:#d9d9d9:#262626:#dbbdbd:#bddbbd:#dbdbbd:#bdbddb:#dbbddb:#bddbdb:#ffffff",
+      "background_color": "#0d1926",
+      "cursor_color": "#d9e6f2",
+      "foreground_color": "#d9e6f2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Blitz",
+      "background_color": "#16141e",
+      "cursor_color": "#00ecc8",
+      "foreground_color": "#00ecc8",
+      "palette": "#2e3436:#f70047:#00ff7d:#fcdd42:#26b3d2:#b055f4:#ff8db4:#d3d7cf:#555753:#ff5555:#55ff55:#ffff55:#729fcf:#ff55ff:#34e2e2:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "Bloody",
+      "background_color": "#1e1f29",
+      "background_image": "None",
+      "cursor_color": "#f9dc5c",
+      "foreground_color": "#aaaaaa",
+      "palette": "#2e3436:#ff512f:#b2ffa9:#fffd82:#3185fc:#dd2476:#66d7d1:#f2efea:#555753:#ff512f:#b2ffa9:#fffd82:#3185fc:#dd2476:#66d7d1:#f2efea",
+      "type": "dark"
+    },
+    {
+      "name": "Borland",
+      "palette": "#4f4f4f:#ff6c60:#a8ff60:#ffffb6:#96cbfe:#ff73fd:#c6c5fe:#eeeeee:#7c7c7c:#ffb6b0:#ceffac:#ffffcc:#b5dcff:#ff9cfe:#dfdffe:#ffffff",
+      "background_color": "#0000a4",
+      "cursor_color": "#ffa560",
+      "foreground_color": "#ffff4e",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Bright Lights",
+      "palette": "#191919:#ff355b:#b7e876:#ffc251:#76d4ff:#ba76e7:#6cbfb5:#c2c8d7:#191919:#ff355b:#b7e876:#ffc251:#76d5ff:#ba76e7:#6cbfb5:#c2c8d7",
+      "background_color": "#191919",
+      "cursor_color": "#f34b00",
+      "foreground_color": "#b3c9d7",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Broadcast",
+      "palette": "#000000:#da4939:#519f50:#ffd24a:#6d9cbe:#d0d0ff:#6e9cbe:#ffffff:#323232:#ff7b6b:#83d182:#ffff7c:#9fcef0:#ffffff:#a0cef0:#ffffff",
+      "background_color": "#2b2b2b",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#e6e1dc",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Brogrammer",
+      "palette": "#1f1f1f:#f81118:#2dc55e:#ecba0f:#2a84d2:#4e5ab7:#1081d6:#d6dbe5:#d6dbe5:#de352e:#1dd361:#f3bd09:#1081d6:#5350b9:#0f7ddb:#ffffff",
+      "background_color": "#131313",
+      "cursor_color": "#b9b9b9",
+      "foreground_color": "#d6dbe5",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "C64",
+      "palette": "#090300:#883932:#55a049:#bfce72:#40318d:#8b3f96:#67b6bd:#ffffff:#000000:#883932:#55a049:#bfce72:#40318d:#8b3f96:#67b6bd:#f7f7f7",
+      "background_color": "#40318d",
+      "cursor_color": "#7869c4",
+      "foreground_color": "#7869c4",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Cai",
+      "background_color": "#09111a",
+      "background_image": "None",
+      "cursor_color": "#e3eef9",
+      "foreground_color": "#d9e6f2",
+      "palette": "#000000:#ca274d:#4dca27:#caa427:#274dca:#a427ca:#27caa4:#808080:#808080:#e98da3:#a3e98d:#e9d48d:#8da3e9:#d48de9:#8de9d4:#ffffff",
+      "type": "dark"
+    },
+    {
+      "name": "Candy",
+      "background_color": "#000000",
+      "foreground_color": "#AAAAAA",
+      "cursor_color": "#aaaaaa",
+      "palette": "#2e3436:#fa2573:#a6e32d:#fc951e:#c48dff:#fa2573:#67d9f0:#f2f2f2:#555753:#fa2573:#8ae234:#fce94f:#729fcf:#fa2573:#34e2e2:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "Chalk",
+      "palette": "#7d8b8f:#b23a52:#789b6a:#b9ac4a:#2a7fac:#bd4f5a:#44a799:#d2d8d9:#888888:#f24840:#80c470:#ffeb62:#4196ff:#fc5275:#53cdbd:#d2d8d9",
+      "background_color": "#2b2d2e",
+      "cursor_color": "#708284",
+      "foreground_color": "#d2d8d9",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Chalkboard",
+      "palette": "#000000:#c37372:#72c373:#c2c372:#7372c3:#c372c2:#72c2c3:#d9d9d9:#323232:#dbaaaa:#aadbaa:#dadbaa:#aaaadb:#dbaada:#aadadb:#ffffff",
+      "background_color": "#29262f",
+      "cursor_color": "#d9e6f2",
+      "foreground_color": "#d9e6f2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Chalkby",
+      "background_color": "#1f2d2d",
+      "cursor_color": "#ffffff",
+      "cursor_color_fg": "False",
+      "foreground_color": "#ffffff",
+      "palette": "#2e3436:#ffb0b0:#c8ff9b:#fffca4:#6f9ceb:#9395d3:#bdeaff:#d3d7cf:#555753:#ffb0b0:#c8ff9b:#fffca4:#6f9ceb:#9395d3:#bdeaff:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "Chesterish",
+      "background_color": "#293340",
+      "background_image": "None",
+      "cursor_color": "#2c85f7",
+      "foreground_color": "#cdd2e9",
+      "palette": "#293340:#e17e85:#61ba86:#ffec8e:#4cb2ff:#be86e3:#2dced0:#cdd2e9:#546386:#e17e85:#61ba86:#ffec8e:#4cb2ff:#be86e3:#2dced0:#cdd2e9",
+      "type": "dark"
+    },
+    {
+      "name": "Ciapre",
+      "palette": "#181818:#810009:#48513b:#cc8b3f:#576d8c:#724d7c:#5c4f4b:#aea47f:#555555:#ac3835:#a6a75d:#dcdf7c:#3097c6:#d33061:#f3dbb2:#f4f4f4",
+      "background_color": "#191c27",
+      "cursor_color": "#92805b",
+      "foreground_color": "#aea47a",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "CLRS",
+      "palette": "#000000:#f8282a:#328a5d:#fa701d:#135cd0:#9f00bd:#33c3c1:#b3b3b3:#555753:#fb0416:#2cc631:#fdd727:#1670ff:#e900b0:#3ad5ce:#eeeeec",
+      "background_color": "#ffffff",
+      "cursor_color": "#6fd3fc",
+      "foreground_color": "#262626",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Cobalt Neon",
+      "palette": "#142631:#ff2320:#3ba5ff:#e9e75c:#8ff586:#781aa0:#8ff586:#ba46b2:#fff688:#d4312e:#8ff586:#e9f06d:#3c7dd2:#8230a7:#6cbc67:#8ff586",
+      "background_color": "#142838",
+      "cursor_color": "#c4206f",
+      "foreground_color": "#8ff586",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Cobalt2",
+      "palette": "#000000:#ff0000:#38de21:#ffe50a:#1460d2:#ff005d:#00bbbb:#bbbbbb:#555555:#f40e17:#3bd01d:#edc809:#5555ff:#ff55ff:#6ae3fa:#ffffff",
+      "background_color": "#132738",
+      "cursor_color": "#f0cc09",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "CrayonPonyFish",
+      "palette": "#2b1b1d:#91002b:#579524:#ab311b:#8c87b0:#692f50:#e8a866:#68525a:#3d2b2e:#c5255d:#8dff57:#c8381d:#cfc9ff:#fc6cba:#ffceaf:#b0949d",
+      "background_color": "#150707",
+      "cursor_color": "#68525a",
+      "foreground_color": "#68525a",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Dark Pastel",
+      "palette": "#000000:#ff5555:#55ff55:#ffff55:#5555ff:#ff55ff:#55ffff:#bbbbbb:#555555:#ff5555:#55ff55:#ffff55:#5555ff:#ff55ff:#55ffff:#ffffff",
+      "background_color": "#000000",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Darkside",
+      "palette": "#000000:#e8341c:#68c256:#f2d42c:#1c98e8:#8e69c9:#1c98e8:#bababa:#000000:#e05a4f:#77b869:#efd64b:#387cd3:#957bbe:#3d97e2:#bababa",
+      "background_color": "#222324",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#bababa",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "deep",
+      "palette": "#000000:#d70005:#1cd915:#d9bd26:#5665ff:#b052da:#50d2da:#e0e0e0:#535353:#fb0007:#22ff18:#fedc2b:#9fa9ff:#e09aff:#8df9ff:#ffffff",
+      "background_color": "#090909",
+      "cursor_color": "#d0d0d0",
+      "foreground_color": "#cdcdcd",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Desert",
+      "palette": "#4d4d4d:#ff2b2b:#98fb98:#f0e68c:#cd853f:#ffdead:#ffa0a0:#f5deb3:#555555:#ff5555:#55ff55:#ffff55:#87ceff:#ff55ff:#ffd700:#ffffff",
+      "background_color": "#333333",
+      "cursor_color": "#00ff00",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "DimmedMonokai",
+      "palette": "#3a3d43:#be3f48:#879a3b:#c5a635:#4f76a1:#855c8d:#578fa4:#b9bcba:#888987:#fb001f:#0f722f:#c47033:#186de3:#fb0067:#2e706d:#fdffb9",
+      "background_color": "#1f1f1f",
+      "cursor_color": "#f83e19",
+      "foreground_color": "#b9bcba",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "DotGov",
+      "palette": "#191919:#bf091d:#3d9751:#f6bb34:#17b2e0:#7830b0:#8bd2ed:#ffffff:#191919:#bf091d:#3d9751:#f6bb34:#17b2e0:#7830b0:#8bd2ed:#ffffff",
+      "background_color": "#262c35",
+      "cursor_color": "#d9002f",
+      "foreground_color": "#ebebeb",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Dracula",
+      "background_color": "#1e1f29",
+      "background_image": "None",
+      "cursor_color": "#aaaaaa",
+      "foreground_color": "#f8f8f2",
+      "palette": "#44475a:#ff5555:#50fa7b:#f1fa8c:#8be9fd:#bd93f9:#ff79c6:#94a3a5:#000000:#ff5555:#50fa7b:#f1fa8c:#8be9fd:#bd93f9:#ff79c6:#ffffff",
+      "type": "dark"
+    },
+    {
+      "name": "Duotone Dark",
+      "palette": "#1f1d27:#d9393e:#2dcd73:#d9b76e:#ffc284:#de8d40:#2488ff:#b7a1ff:#353147:#d9393e:#2dcd73:#d9b76e:#ffc284:#de8d40:#2488ff:#eae5ff",
+      "background_color": "#1f1d27",
+      "cursor_color": "#ff9839",
+      "foreground_color": "#b7a1ff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Earthsong",
+      "palette": "#121418:#c94234:#85c54c:#f5ae2e:#1398b9:#d0633d:#509552:#e5c6aa:#675f54:#ff645a:#98e036:#e0d561:#5fdaff:#ff9269:#84f088:#f6f7ec",
+      "background_color": "#292520",
+      "cursor_color": "#f6f7ec",
+      "foreground_color": "#e5c7a9",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Elemental",
+      "palette": "#3c3c30:#98290f:#479a43:#7f7111:#497f7d:#7f4e2f:#387f58:#807974:#555445:#e0502a:#61e070:#d69927:#79d9d9:#cd7c54:#59d599:#fff1e9",
+      "background_color": "#22211d",
+      "cursor_color": "#facb80",
+      "foreground_color": "#807a74",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Elementary",
+      "palette": "#242424:#d71c15:#5aa513:#fdb40c:#063b8c:#e40038:#2595e1:#efefef:#4b4b4b:#fc1c18:#6bc219:#fec80e:#0955ff:#fb0050:#3ea8fc:#8c00ec",
+      "background_color": "#181818",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#efefef",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Elio",
+      "background_color": "#041a3b",
+      "background_image": "None",
+      "cursor_color": "#fbfbfb",
+      "foreground_color": "#f2f2f2",
+      "palette": "#303030:#e1321a:#6ab017:#ffc005:#729FCF:#ec0048:#2aa7e7:#f2f2f2:#5d5d5d:#ff361e:#7bc91f:#ffd00a:#0071ff:#ff1d62:#4bb8fd:#a020f0",
+      "type": "dark"
+    },
+    {
+      "name": "ENCOM",
+      "palette": "#000000:#9f0000:#008b00:#ffd000:#0081ff:#bc00ca:#008b8b:#bbbbbb:#555555:#ff0000:#00ee00:#ffff00:#0000ff:#ff00ff:#00cdcd:#ffffff",
+      "background_color": "#000000",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#00a595",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Espresso",
+      "palette": "#353535:#d25252:#a5c261:#ffc66d:#6c99bb:#d197d9:#bed6ff:#eeeeec:#535353:#f00c0c:#c2e075:#e1e48b:#8ab7d9:#efb5f7:#dcf4ff:#ffffff",
+      "background_color": "#323232",
+      "cursor_color": "#d6d6d6",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Espresso Libre",
+      "palette": "#000000:#cc0000:#1a921c:#f0e53a:#0066ff:#c5656b:#06989a:#d3d7cf:#555753:#ef2929:#9aff87:#fffb5c:#43a8ed:#ff818a:#34e2e2:#eeeeec",
+      "background_color": "#2a211c",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#b8a898",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Fideloper",
+      "palette": "#292f33:#cb1e2d:#edb8ac:#b7ab9b:#2e78c2:#c0236f:#309186:#eae3ce:#092028:#d4605a:#d4605a:#a86671:#7c85c4:#5c5db2:#819090:#fcf4df",
+      "background_color": "#292f33",
+      "cursor_color": "#d4605a",
+      "foreground_color": "#dbdae0",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "FirefoxDev",
+      "palette": "#002831:#e63853:#5eb83c:#a57706:#359ddf:#d75cff:#4b73a2:#dcdcdc:#001e27:#e1003f:#1d9000:#cd9409:#006fc0:#a200da:#005794:#e2e2e2",
+      "background_color": "#0e1011",
+      "cursor_color": "#708284",
+      "foreground_color": "#7c8fa4",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Firewatch",
+      "palette": "#585f6d:#d95360:#5ab977:#dfb563:#4d89c4:#d55119:#44a8b6:#e6e5ff:#585f6d:#d95360:#5ab977:#dfb563:#4c89c5:#d55119:#44a8b6:#e6e5ff",
+      "background_color": "#1e2027",
+      "cursor_color": "#f6f7ec",
+      "foreground_color": "#9ba2b2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "FishTank",
+      "palette": "#03073c:#c6004a:#acf157:#fecd5e:#525fb8:#986f82:#968763:#ecf0fc:#6c5b30:#da4b8a:#dbffa9:#fee6a9:#b2befa:#fda5cd:#a5bd86:#f6ffec",
+      "background_color": "#232537",
+      "cursor_color": "#fecd5e",
+      "foreground_color": "#ecf0fe",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Flat",
+      "palette": "#222d3f:#a82320:#32a548:#e58d11:#3167ac:#781aa0:#2c9370:#b0b6ba:#212c3c:#d4312e:#2d9440:#e5be0c:#3c7dd2:#8230a7:#35b387:#e7eced",
+      "background_color": "#002240",
+      "cursor_color": "#e5be0c",
+      "foreground_color": "#2cc55d",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Flatland",
+      "palette": "#1d1d19:#f18339:#9fd364:#f4ef6d:#5096be:#695abc:#d63865:#ffffff:#1d1d19:#d22a24:#a7d42c:#ff8949:#61b9d0:#695abc:#d63865:#ffffff",
+      "background_color": "#1d1f21",
+      "cursor_color": "#708284",
+      "foreground_color": "#b8dbef",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Floraverse",
+      "palette": "#08002e:#64002c:#5d731a:#cd751c:#1d6da1:#b7077e:#42a38c:#f3e0b8:#331e4d:#d02063:#b4ce59:#fac357:#40a4cf:#f12aae:#62caa8:#fff5db",
+      "background_color": "#0e0d15",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#dbd1b9",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "ForestBlue",
+      "palette": "#333333:#f8818e:#92d3a2:#1a8e63:#8ed0ce:#5e468c:#31658c:#e2d8cd:#3d3d3d:#fb3d66:#6bb48d:#30c85a:#39a7a2:#7e62b3:#6096bf:#e2d8cd",
+      "background_color": "#051519",
+      "cursor_color": "#9e9ecb",
+      "foreground_color": "#e2d8cd",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Freya",
+      "background_color": "#252e32",
+      "background_image": "None",
+      "cursor_color": "#839496",
+      "foreground_color": "#94a3a5",
+      "palette": "#073642:#dc322f:#859900:#b58900:#268bd2:#ec0048:#2aa198:#94a3a5:#586e75:#cb4b16:#859900:#b58900:#268bd2:#d33682:#2aa198:#6c71c4",
+      "type": "dark"
+    },
+    {
+      "name": "FrontEndDelight",
+      "palette": "#242526:#f8511b:#565747:#fa771d:#2c70b7:#f02e4f:#3ca1a6:#adadad:#5fac6d:#f74319:#74ec4c:#fdc325:#3393ca:#e75e4f:#4fbce6:#8c735b",
+      "background_color": "#1b1c1d",
+      "cursor_color": "#cdcdcd",
+      "foreground_color": "#adadad",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "FunForrest",
+      "palette": "#000000:#d6262b:#919c00:#be8a13:#4699a3:#8d4331:#da8213:#ddc265:#7f6a55:#e55a1c:#bfc65a:#ffcb1b:#7cc9cf:#d26349:#e6a96b:#ffeaa3",
+      "background_color": "#251200",
+      "cursor_color": "#e5591c",
+      "foreground_color": "#dec165",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Galaxy",
+      "palette": "#000000:#f9555f:#21b089:#fef02a:#589df6:#944d95:#1f9ee7:#bbbbbb:#555555:#fa8c8f:#35bb9a:#ffff55:#589df6:#e75699:#3979bc:#ffffff",
+      "background_color": "#1d2837",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Github",
+      "palette": "#3e3e3e:#970b16:#07962a:#f8eec7:#003e8a:#e94691:#89d1ec:#ffffff:#666666:#de0000:#87d5a2:#f1d007:#2e6cba:#ffa29f:#1cfafe:#ffffff",
+      "background_color": "#f4f4f4",
+      "cursor_color": "#3f3f3f",
+      "foreground_color": "#3e3e3e",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Glacier",
+      "palette": "#2e343c:#bd0f2f:#35a770:#fb9435:#1f5872:#bd2523:#778397:#ffffff:#404a55:#bd0f2f:#49e998:#fddf6e:#2a8bc1:#ea4727:#a0b6d3:#ffffff",
+      "background_color": "#0c1115",
+      "cursor_color": "#6c6c6c",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Grape",
+      "palette": "#2d283f:#ed2261:#1fa91b:#8ddc20:#487df4:#8d35c9:#3bdeed:#9e9ea0:#59516a:#f0729a:#53aa5e:#b2dc87:#a9bcec:#ad81c2:#9de3eb:#a288f7",
+      "background_color": "#171423",
+      "cursor_color": "#a288f7",
+      "foreground_color": "#9f9fa1",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Grass",
+      "palette": "#000000:#bb0000:#00bb00:#e7b000:#0000a3:#950062:#00bbbb:#bbbbbb:#555555:#bb0000:#00bb00:#e7b000:#0000bb:#ff55ff:#55ffff:#ffffff",
+      "background_color": "#13773d",
+      "cursor_color": "#8c2800",
+      "foreground_color": "#fff0a5",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Gruvbox Dark",
+      "palette": "#161819:#f73028:#aab01e:#f7b125:#719586:#c77089:#7db669:#faefbb:#7f7061:#be0f17:#868715:#cc881a:#377375:#a04b73:#578e57:#e6d4a3",
+      "background_color": "#1e1e1e",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#e6d4a3",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Hardcore",
+      "palette": "#1b1d1e:#f92672:#a6e22e:#fd971f:#66d9ef:#9e6ffe:#5e7175:#ccccc6:#505354:#ff669d:#beed5f:#e6db74:#66d9ef:#9e6ffe:#a3babf:#f8f8f2",
+      "background_color": "#121212",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#a0a0a0",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Harper",
+      "palette": "#010101:#f8b63f:#7fb5e1:#d6da25:#489e48:#b296c6:#f5bfd7:#a8a49d:#726e6a:#f8b63f:#7fb5e1:#d6da25:#489e48:#b296c6:#f5bfd7:#fefbea",
+      "background_color": "#010101",
+      "cursor_color": "#a8a49d",
+      "foreground_color": "#a8a49d",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Hemisu dark",
+      "background_image": "None",
+      "cursor_color": "#BAFFAA",
+      "foreground_color": "#FFFFFF",
+      "palette": "#444444:#FF0054:#B1D630:#9D895E:#67BEE3:#B576BC:#569A9F:#EDEDED:#777777:#D65E75:#BAFFAA:#ECE1C8:#9FD3E5:#DEB3DF:#B6E0E5:#FFFFFF",
+      "type": "dark"
+    },
+    {
+      "name": "Hemisu light",
+      "background_color": "#EFEFEF",
+      "background_image": "None",
+      "cursor_color": "#FF0054",
+      "foreground_color": "#444444",
+      "palette": "#777777:#FF0055:#739100:#503D15:#538091:#5B345E:#538091:#999999:#999999:#D65E76:#9CC700:#947555:#9DB3CD:#A184A4:#85B2AA:#BABABA",
+      "type": "light"
+    },
+    {
+      "name": "Highway",
+      "palette": "#000000:#d00e18:#138034:#ffcb3e:#006bb3:#6b2775:#384564:#ededed:#5d504a:#f07e18:#b1d130:#fff120:#4fc2fd:#de0071:#5d504a:#ffffff",
+      "background_color": "#222225",
+      "cursor_color": "#e0d9b9",
+      "foreground_color": "#ededed",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Hipster Green",
+      "palette": "#000000:#b6214a:#00a600:#bfbf00:#246eb2:#b200b2:#00a6b2:#bfbfbf:#666666:#e50000:#86a93e:#e5e500:#0000ff:#e500e5:#00e5e5:#e5e5e5",
+      "background_color": "#100b05",
+      "cursor_color": "#23ff18",
+      "foreground_color": "#84c138",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Homebrew",
+      "palette": "#000000:#990000:#00a600:#999900:#0000b2:#b200b2:#00a6b2:#bfbfbf:#666666:#e50000:#00d900:#e5e500:#0000ff:#e500e5:#00e5e5:#e5e5e5",
+      "background_color": "#000000",
+      "cursor_color": "#23ff18",
+      "foreground_color": "#00ff00",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Hurtado",
+      "palette": "#575757:#ff1b00:#a5e055:#fbe74a:#496487:#fd5ff1:#86e9fe:#cbcccb:#262626:#d51d00:#a5df55:#fbe84a:#89beff:#c001c1:#86eafe:#dbdbdb",
+      "background_color": "#000000",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#dbdbdb",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Hybrid",
+      "palette": "#2a2e33:#b84d51:#b3bf5a:#e4b55e:#6e90b0:#a17eac:#7fbfb4:#b5b9b6:#1d1f22:#8d2e32:#798431:#e58a50:#4b6b88:#6e5079:#4d7b74:#5a626a",
+      "background_color": "#161719",
+      "cursor_color": "#b7bcba",
+      "foreground_color": "#b7bcba",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "IC_Green_PPL",
+      "palette": "#1f1f1f:#fb002a:#339c24:#659b25:#149b45:#53b82c:#2cb868:#e0ffef:#032710:#a7ff3f:#9fff6d:#d2ff6d:#72ffb5:#50ff3e:#22ff71:#daefd0",
+      "background_color": "#3a3d3f",
+      "cursor_color": "#42ff58",
+      "foreground_color": "#d9efd3",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "IC_Orange_PPL",
+      "palette": "#000000:#c13900:#a4a900:#caaf00:#bd6d00:#fc5e00:#f79500:#ffc88a:#6a4f2a:#ff8c68:#f6ff40:#ffe36e:#ffbe55:#fc874f:#c69752:#fafaff",
+      "background_color": "#262626",
+      "cursor_color": "#fc531d",
+      "foreground_color": "#ffcb83",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "idleToes",
+      "palette": "#323232:#d25252:#7fe173:#ffc66d:#4099ff:#f680ff:#bed6ff:#eeeeec:#535353:#f07070:#9dff91:#ffe48b:#5eb7f7:#ff9dff:#dcf4ff:#ffffff",
+      "background_color": "#323232",
+      "cursor_color": "#d6d6d6",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "IR_Black",
+      "palette": "#4f4f4f:#fa6c60:#a8ff60:#fffeb7:#96cafe:#fa73fd:#c6c5fe:#efedef:#7b7b7b:#fcb6b0:#cfffab:#ffffcc:#b5dcff:#fb9cfe:#e0e0fe:#ffffff",
+      "background_color": "#000000",
+      "cursor_color": "#808080",
+      "foreground_color": "#f1f1f1",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Jackie Brown",
+      "palette": "#2c1d16:#ef5734:#2baf2b:#bebf00:#246eb2:#d05ec1:#00acee:#bfbfbf:#666666:#e50000:#86a93e:#e5e500:#0000ff:#e500e5:#00e5e5:#e5e5e5",
+      "background_color": "#2c1d16",
+      "cursor_color": "#23ff18",
+      "foreground_color": "#ffcc2f",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Japanesque",
+      "palette": "#343935:#cf3f61:#7bb75b:#e9b32a:#4c9ad4:#a57fc4:#389aad:#fafaf6:#595b59:#d18fa6:#767f2c:#78592f:#135979:#604291:#76bbca:#b2b5ae",
+      "background_color": "#1e1e1e",
+      "cursor_color": "#edcf4f",
+      "foreground_color": "#f7f6ec",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Jellybeans",
+      "palette": "#929292:#e27373:#94b979:#ffba7b:#97bedc:#e1c0fa:#00988e:#dedede:#bdbdbd:#ffa1a1:#bddeab:#ffdca0:#b1d8f6:#fbdaff:#1ab2a8:#ffffff",
+      "background_color": "#121212",
+      "cursor_color": "#ffa560",
+      "foreground_color": "#dedede",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "JetBrains Darcula",
+      "palette": "#000000:#fa5355:#126e00:#c2c300:#4581eb:#fa54ff:#33c2c1:#adadad:#555555:#fb7172:#67ff4f:#ffff00:#6d9df1:#fb82ff:#60d3d1:#eeeeee",
+      "background_color": "#202020",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#adadad",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Juicy",
+      "background_color": "#212121",
+      "cursor_color": "#fcfcfc",
+      "foreground_color": "#fcfcfc",
+      "palette": "#2e3436:#ff0945:#1aff81:#fff64a:#2bf1ff:#7b68ee:#98f4ff:#d3d7cf:#555753:#ff0945:#1aff81:#fff64a:#2bf1ff:#7b68ee:#98f4ff:#eeeeec",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Kibble",
+      "palette": "#4d4d4d:#c70031:#29cf13:#d8e30e:#3449d1:#8400ff:#0798ab:#e2d1e3:#5a5a5a:#f01578:#6ce05c:#f3f79e:#97a4f7:#c495f0:#68f2e0:#ffffff",
+      "background_color": "#0e100a",
+      "cursor_color": "#9fda9c",
+      "foreground_color": "#f7f7f7",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Later This Evening",
+      "palette": "#2b2b2b:#d45a60:#afba67:#e5d289:#a0bad6:#c092d6:#91bfb7:#3c3d3d:#454747:#d3232f:#aabb39:#e5be39:#6699d6:#ab53d6:#5fc0ae:#c1c2c2",
+      "background_color": "#222222",
+      "cursor_color": "#424242",
+      "foreground_color": "#959595",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Lavandula",
+      "palette": "#230046:#7d1625:#337e6f:#7f6f49:#4f4a7f:#5a3f7f:#58777f:#736e7d:#372d46:#e05167:#52e0c4:#e0c386:#8e87e0:#a776e0:#9ad4e0:#8c91fa",
+      "background_color": "#050014",
+      "cursor_color": "#8c91fa",
+      "foreground_color": "#736e7d",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "LiquidCarbon",
+      "palette": "#000000:#ff3030:#559a70:#ccac00:#0099cc:#cc69c8:#7ac4cc:#bccccc:#000000:#ff3030:#559a70:#ccac00:#0099cc:#cc69c8:#7ac4cc:#bccccc",
+      "background_color": "#303030",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#afc2c2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "LiquidCarbonTransparent",
+      "palette": "#000000:#ff3030:#559a70:#ccac00:#0099cc:#cc69c8:#7ac4cc:#bccccc:#000000:#ff3030:#559a70:#ccac00:#0099cc:#cc69c8:#7ac4cc:#bccccc",
+      "background_color": "#000000",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#afc2c2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "LiquidCarbonTransparentInverse",
+      "palette": "#bccccd:#ff3030:#559a70:#ccac00:#0099cc:#cc69c8:#7ac4cc:#000000:#ffffff:#ff3030:#559a70:#ccac00:#0099cc:#cc69c8:#7ac4cc:#000000",
+      "background_color": "#000000",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#afc2c2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Lucy",
+      "background_color": "#1a1b23",
+      "cursor_color": "#af98e6",
+      "foreground_color": "#96979b",
+      "palette": "#2e3436:#fb7da7:#76c5a4:#e8d56d:#3465a4:#af98e6:#56c9db:#d3d7cf:#555753:#fb7da7:#76c5a4:#e8d56d:#729fcf:#af98e6:#56c9db:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "Man Page",
+      "palette": "#000000:#cc0000:#00a600:#999900:#0000b2:#b200b2:#00a6b2:#cccccc:#666666:#e50000:#00d900:#e5e500:#0000ff:#e500e5:#00e5e5:#e5e5e5",
+      "background_color": "#fef49c",
+      "cursor_color": "#7f7f7f",
+      "foreground_color": "#000000",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Mar",
+      "background_color": "#ffffff",
+      "background_image": "None",
+      "cursor_color": "#23476a",
+      "foreground_color": "#23476a",
+      "palette": "#000000:#b5407b:#7bb540:#b57b40:#407bb5:#7b40b5:#40b57b:#f8f8f8:#737373:#cd73a0:#a0cd73:#cda073:#73a0cd:#a073cd:#73cda0:#ffffff",
+      "type": "light"
+    },
+    {
+      "name": "Material",
+      "palette": "#212121:#b7141f:#457b24:#f6981e:#134eb2:#560088:#0e717c:#efefef:#424242:#e83b3f:#7aba3a:#ffea2e:#54a4f3:#aa4dbc:#26bbd1:#d9d9d9",
+      "background_color": "#eaeaea",
+      "cursor_color": "#16afca",
+      "foreground_color": "#232322",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Material colors",
+      "background_color": "#1E282C",
+      "background_image": "None",
+      "cursor_color": "#657B83",
+      "foreground_color": "#C3C7D1",
+      "palette": "#073641:#EB606B:#C3E88D:#F7EB95:#80CBC3:#FF2490:#AEDDFF:#FFFFFF:#002B36:#EB606B:#C3E88D:#F7EB95:#7DC6BF:#6C71C3:#34434D:#FFFFFF",
+      "type": "dark"
+    },
+    {
+      "name": "Material-Ocean",
+      "background_color": "#0f111a",
+      "cursor_color": "#ffcc00",
+      "cursor_color_fg": "False",
+      "foreground_color": "#8f93a2",
+      "palette": "#2e3436:#ff5370:#c3e88d:#ffcb6b:#82aaff:#c792ea:#89ddff:#d3d7cf:#555753:#f07178:#c3e88d:#f78c6c:#729fcf:#bb80b3:#89ddff:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "Material-Palenight",
+      "background_color": "#292d3e",
+      "cursor_color": "#ffcc00",
+      "cursor_color_fg": "False",
+      "foreground_color": "#a6accd",
+      "palette": "#2e3436:#ff5370:#c3e88d:#ffcb6b:#82aaff:#c792ea:#89ddff:#d3d7cf:#555753:#f07178:#c3e88d:#f78c6c:#729fcf:#bb80b3:#89ddff:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "MaterialDark",
+      "palette": "#212121:#b7141f:#457b24:#f6981e:#134eb2:#560088:#0e717c:#efefef:#424242:#e83b3f:#7aba3a:#ffea2e:#54a4f3:#aa4dbc:#26bbd1:#d9d9d9",
+      "background_color": "#232322",
+      "cursor_color": "#16afca",
+      "foreground_color": "#e5e5e5",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Mathias",
+      "palette": "#000000:#e52222:#a6e32d:#fc951e:#c48dff:#fa2573:#67d9f0:#f2f2f2:#555555:#ff5555:#55ff55:#ffff55:#5555ff:#ff55ff:#55ffff:#ffffff",
+      "background_color": "#000000",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#bbbbbb",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Medallion",
+      "palette": "#000000:#b64c00:#7c8b16:#d3bd26:#616bb0:#8c5a90:#916c25:#cac29a:#5e5219:#ff9149:#b2ca3b:#ffe54a:#acb8ff:#ffa0ff:#ffbc51:#fed698",
+      "background_color": "#1d1908",
+      "cursor_color": "#d3ba30",
+      "foreground_color": "#cac296",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Misterioso",
+      "palette": "#000000:#ff4242:#74af68:#ffad29:#338f86:#9414e6:#23d7d7:#e1e1e0:#555555:#ff3242:#74cd68:#ffb929:#23d7d7:#ff37ff:#00ede1:#ffffff",
+      "background_color": "#2d3743",
+      "cursor_color": "#000000",
+      "foreground_color": "#e1e1e0",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Miu",
+      "background_color": "#0d1926",
+      "background_image": "None",
+      "cursor_color": "#d7dee4",
+      "foreground_color": "#d9e6f2",
+      "palette": "#000000:#b87a7a:#7ab87a:#b8b87a:#7a7ab8:#b87ab8:#7ab8b8:#d9d9d9:#262626:#dbbdbd:#bddbbd:#dbdbbd:#bdbddb:#dbbddb:#bddbdb:#ffffff",
+      "type": "dark"
+    },
+    {
+      "name": "Molokai",
+      "palette": "#121212:#fa2573:#98e123:#dfd460:#1080d0:#8700ff:#43a8d0:#bbbbbb:#555555:#f6669d:#b1e05f:#fff26d:#00afff:#af87ff:#51ceff:#ffffff",
+      "background_color": "#121212",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#bbbbbb",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "MonaLisa",
+      "palette": "#351b0e:#9b291c:#636232:#c36e28:#515c5d:#9b1d29:#588056:#f7d75c:#874228:#ff4331:#b4b264:#ff9566:#9eb2b4:#ff5b6a:#8acd8f:#ffe598",
+      "background_color": "#120b0d",
+      "cursor_color": "#c46c32",
+      "foreground_color": "#f7d66a",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Monokai dark",
+      "background_color": "#272822",
+      "background_image": "None",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#f8f8f2",
+      "palette": "#75715e:#f92672:#a6e22e:#f4bf75:#66d9ef:#ae81ff:#2aa198:#f9f8f5:#272822:#f92672:#a6e22e:#f4bf75:#66d9ef:#ae81ff:#2aa198:#f9f8f5",
+      "type": "dark"
+    },
+    {
+      "name": "Monokai Soda",
+      "palette": "#1a1a1a:#f4005f:#98e024:#fa8419:#9d65ff:#f4005f:#58d1eb:#c4c5b5:#625e4c:#f4005f:#98e024:#e0d561:#9d65ff:#f4005f:#58d1eb:#f6f6ef",
+      "background_color": "#1a1a1a",
+      "cursor_color": "#f6f7ec",
+      "foreground_color": "#c4c5b5",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Monokai Vivid",
+      "palette": "#121212:#fa2934:#98e123:#fff30a:#0443ff:#f800f8:#01b6ed:#ffffff:#838383:#f6669d:#b1e05f:#fff26d:#0443ff:#f200f6:#51ceff:#ffffff",
+      "background_color": "#121212",
+      "cursor_color": "#fb0007",
+      "foreground_color": "#f9f9f9",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "N0tch2k",
+      "palette": "#383838:#a95551:#666666:#a98051:#657d3e:#767676:#c9c9c9:#d0b8a3:#474747:#a97775:#8c8c8c:#a99175:#98bd5e:#a3a3a3:#dcdcdc:#d8c8bb",
+      "background_color": "#222222",
+      "cursor_color": "#aa9175",
+      "foreground_color": "#a0a0a0",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Nebula",
+      "background_color": "#23262e",
+      "cursor_color": "#00e8c6",
+      "foreground_color": "#ffffff",
+      "palette": "#2e3436:#ff007a:#84ff39:#f3d56e:#7cb7ff:#c74ded:#00e8c6:#d3d7cf:#555753:#ff007a:#84ff39:#f3d56e:#7cb7ff:#c74ded:#00e8c6:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "Neopolitan",
+      "palette": "#000000:#800000:#61ce3c:#fbde2d:#253b76:#ff0080:#8da6ce:#f8f8f8:#000000:#800000:#61ce3c:#fbde2d:#253b76:#ff0080:#8da6ce:#f8f8f8",
+      "background_color": "#271f19",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Neutron",
+      "palette": "#23252b:#b54036:#5ab977:#deb566:#6a7c93:#a4799d:#3f94a8:#e6e8ef:#23252b:#b54036:#5ab977:#deb566:#6a7c93:#a4799d:#3f94a8:#ebedf2",
+      "background_color": "#1c1e22",
+      "cursor_color": "#f6f7ec",
+      "foreground_color": "#e6e8ef",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Night Owl",
+      "background_color": "#011627",
+      "cursor_color": "#80a4c2",
+      "cursor_color_fg": "False",
+      "foreground_color": "#d6deeb",
+      "palette": "#2e3436:#ef5350:#80cbc4:#ffeb95:#82aaff:#c792ea:#addb67:#d3d7cf:#555753:#ef5350:#80cbc4:#ffeb95:#82aaff:#c792ea:#addb67:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "NightLion v1",
+      "palette": "#4c4c4c:#bb0000:#5fde8f:#f3f167:#276bd8:#bb00bb:#00dadf:#bbbbbb:#555555:#ff5555:#55ff55:#ffff55:#5555ff:#ff55ff:#55ffff:#ffffff",
+      "background_color": "#000000",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#bbbbbb",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "NightLion v2",
+      "palette": "#4c4c4c:#bb0000:#04f623:#f3f167:#64d0f0:#ce6fdb:#00dadf:#bbbbbb:#555555:#ff5555:#7df71d:#ffff55:#62cbe8:#ff9bf5:#00ccd8:#ffffff",
+      "background_color": "#171717",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#bbbbbb",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Nord",
+      "background_color": "#2E3440",
+      "cursor_color": "#D8DEE9",
+      "foreground_color": "#D8DEE9",
+      "palette": "#3B4252:#BF616A:#A3BE8C:#EBCB8B:#81A1C1:#B48EAD:#88C0D0:#E5E9F0:#4C566A:#BF616A:#A3BE8C:#EBCB8B:#81A1C1:#B48EAD:#8FBCBB:#ECEFF4",
+      "type": "dark"
+    },
+    {
+      "name": "Novel",
+      "palette": "#000000:#cc0000:#009600:#d06b00:#0000cc:#cc00cc:#0087cc:#cccccc:#808080:#cc0000:#009600:#d06b00:#0000cc:#cc00cc:#0087cc:#ffffff",
+      "background_color": "#dfdbc3",
+      "cursor_color": "#73635a",
+      "foreground_color": "#3b2322",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Obsidian",
+      "palette": "#000000:#a60001:#00bb00:#fecd22:#3a9bdb:#bb00bb:#00bbbb:#bbbbbb:#555555:#ff0003:#93c863:#fef874:#a1d7ff:#ff55ff:#55ffff:#ffffff",
+      "background_color": "#283033",
+      "cursor_color": "#c0cad0",
+      "foreground_color": "#cdcdcd",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Ocean",
+      "palette": "#000000:#990000:#00a600:#999900:#0000b2:#b200b2:#00a6b2:#bfbfbf:#666666:#e50000:#00d900:#e5e500:#0000ff:#e500e5:#00e5e5:#e5e5e5",
+      "background_color": "#224fbc",
+      "cursor_color": "#7f7f7f",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Ocean dark",
+      "background_color": "#1c1f27",
+      "background_image": "None",
+      "cursor_color": "#a0a4b2",
+      "foreground_color": "#979cac",
+      "palette": "#4F4F4F:#AF4B57:#AFD383:#E5C079:#7D90A4:#A4799D:#85A6A5:#EEEDEE:#7B7B7B:#AF4B57:#CEFFAB:#FFFECC:#B5DCFE:#FB9BFE:#DFDFFD:#FEFFFE",
+      "type": "dark"
+    },
+    {
+      "name": "OceanicMaterial",
+      "palette": "#000000:#ee2b2a:#40a33f:#ffea2e:#1e80f0:#8800a0:#16afca:#a4a4a4:#777777:#dc5c60:#70be71:#fff163:#54a4f3:#aa4dbc:#42c7da:#ffffff",
+      "background_color": "#1c262b",
+      "cursor_color": "#b3b8c3",
+      "foreground_color": "#c2c8d7",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Ollie",
+      "palette": "#000000:#ac2e31:#31ac61:#ac4300:#2d57ac:#b08528:#1fa6ac:#8a8eac:#5b3725:#ff3d48:#3bff99:#ff5e1e:#4488ff:#ffc21d:#1ffaff:#5b6ea7",
+      "background_color": "#222125",
+      "cursor_color": "#5b6ea7",
+      "foreground_color": "#8a8dae",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "One dark",
+      "background_color": "#1e2127",
+      "background_image": "None",
+      "cursor_color": "#676c76",
+      "foreground_color": "#5c6370",
+      "palette": "#000000:#e06c75:#98c379:#d19a66:#61afef:#c678dd:#56b6c2:#abb2bf:#5c6370:#e06c75:#98c379:#d19a66:#61afef:#c678dd:#56b6c2:#fffefe",
+      "type": "dark"
+    },
+    {
+      "name": "OneHalfDark",
+      "palette": "#282c34:#e06c75:#98c379:#e5c07b:#61afef:#c678dd:#56b6c2:#dcdfe4:#282c34:#e06c75:#98c379:#e5c07b:#61afef:#c678dd:#56b6c2:#dcdfe4",
+      "background_color": "#282c34",
+      "cursor_color": "#a3b3cc",
+      "foreground_color": "#dcdfe4",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "OneHalfLight",
+      "palette": "#383a42:#e45649:#50a14f:#c18401:#0184bc:#a626a4:#0997b3:#fafafa:#4f525e:#e06c75:#98c379:#e5c07b:#61afef:#c678dd:#56b6c2:#ffffff",
+      "background_color": "#fafafa",
+      "cursor_color": "#bfceff",
+      "foreground_color": "#383a42",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Pali",
+      "background_color": "#232e37",
+      "background_image": "None",
+      "cursor_color": "#e3ecf5",
+      "foreground_color": "#d9e6f2",
+      "palette": "#0a0a0a:#ab8f74:#74ab8f:#8fab74:#8f74ab:#ab748f:#748fab:#f2f2f2:#5d5d5d:#ff1d62:#9cc3af:#ffd00a:#af9cc3:#ff1d62:#4bb8fd:#a020f0",
+      "type": "dark"
+    },
+    {
+      "name": "Panda",
+      "background_color": "#292a2b",
+      "cursor_color": "#f0eeee",
+      "foreground_color": "#e6e6e6",
+      "palette": "#676b79:#ff2c6d:#19f9d8:#ffb86c:#45a9f9:#b084eb:#6fc1ff:#d3d7cf:#676b79:#ff9ac1:#19f9d8:#ffcc95:#45a9f9:#b084eb:#6fc1ff:#eeeeec",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Pandora",
+      "palette": "#000000:#ff4242:#74af68:#ffad29:#338f86:#9414e6:#23d7d7:#e2e2e2:#3f5648:#ff3242:#74cd68:#ffb929:#23d7d7:#ff37ff:#00ede1:#ffffff",
+      "background_color": "#141e43",
+      "cursor_color": "#43d58e",
+      "foreground_color": "#e1e1e1",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Paraiso Dark",
+      "palette": "#2f1e2e:#ef6155:#48b685:#fec418:#06b6ef:#815ba4:#5bc4bf:#a39e9b:#776e71:#ef6155:#48b685:#fec418:#06b6ef:#815ba4:#5bc4bf:#e7e9db",
+      "background_color": "#2f1e2e",
+      "cursor_color": "#a39e9b",
+      "foreground_color": "#a39e9b",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Parasio Dark",
+      "palette": "#2f1e2e:#ef6155:#48b685:#fec418:#06b6ef:#815ba4:#5bc4bf:#a39e9b:#776e71:#ef6155:#48b685:#fec418:#06b6ef:#815ba4:#5bc4bf:#e7e9db",
+      "background_color": "#2f1e2e",
+      "cursor_color": "#a39e9b",
+      "foreground_color": "#a39e9b",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "PaulMillr",
+      "palette": "#2a2a2a:#ff0000:#79ff0f:#e7bf00:#396bd7:#b449be:#66ccff:#bbbbbb:#666666:#ff0080:#66ff66:#f3d64e:#709aed:#db67e6:#7adff2:#ffffff",
+      "background_color": "#000000",
+      "cursor_color": "#4d4d4d",
+      "foreground_color": "#f2f2f2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "PencilDark",
+      "palette": "#212121:#c30771:#10a778:#a89c14:#008ec4:#523c79:#20a5ba:#d9d9d9:#424242:#fb007a:#5fd7af:#f3e430:#20bbfc:#6855de:#4fb8cc:#f1f1f1",
+      "background_color": "#212121",
+      "cursor_color": "#20bbfc",
+      "foreground_color": "#f1f1f1",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "PencilLight",
+      "palette": "#212121:#c30771:#10a778:#a89c14:#008ec4:#523c79:#20a5ba:#d9d9d9:#424242:#fb007a:#5fd7af:#f3e430:#20bbfc:#6855de:#4fb8cc:#f1f1f1",
+      "background_color": "#f1f1f1",
+      "cursor_color": "#20bbfc",
+      "foreground_color": "#424242",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Peppermint",
+      "background_image": "None",
+      "cursor_color": "#BBBBBB",
+      "foreground_color": "#c7c7c7",
+      "palette": "#353535:#E64569:#89D287:#DAB752:#439ECF:#D961DC:#64AAAF:#B3B3B3:#535353:#E4859A:#A2CCA1:#E1E387:#6FBBE2:#E586E7:#96DCDA:#DEDEDE",
+      "type": "dark"
+    },
+    {
+      "name": "Piatto Light",
+      "palette": "#414141:#b23771:#66781e:#cd6f34:#3c5ea8:#a454b2:#66781e:#ffffff:#3f3f3f:#db3365:#829429:#cd6f34:#3c5ea8:#a454b2:#829429:#f2f2f2",
+      "background_color": "#ffffff",
+      "cursor_color": "#5e77c8",
+      "foreground_color": "#414141",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Pnevma",
+      "palette": "#2f2e2d:#a36666:#90a57d:#d7af87:#7fa5bd:#c79ec4:#8adbb4:#d0d0d0:#4a4845:#d78787:#afbea2:#e4c9af:#a1bdce:#d7beda:#b1e7dd:#efefef",
+      "background_color": "#1c1c1c",
+      "cursor_color": "#e4c9af",
+      "foreground_color": "#d0d0d0",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Pro",
+      "palette": "#000000:#990000:#00a600:#999900:#2009db:#b200b2:#00a6b2:#bfbfbf:#666666:#e50000:#00d900:#e5e500:#0000ff:#e500e5:#00e5e5:#e5e5e5",
+      "background_color": "#000000",
+      "cursor_color": "#4d4d4d",
+      "foreground_color": "#f2f2f2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Red Alert",
+      "palette": "#000000:#d62e4e:#71be6b:#beb86b:#489bee:#e979d7:#6bbeb8:#d6d6d6:#262626:#e02553:#aff08c:#dfddb7:#65aaf1:#ddb7df:#b7dfdd:#ffffff",
+      "background_color": "#762423",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Red Planet",
+      "palette": "#202020:#8c3432:#728271:#e8bf6a:#69819e:#896492:#5b8390:#b9aa99:#676767:#b55242:#869985:#ebeb91:#60827e:#de4974:#38add8:#d6bfb8",
+      "background_color": "#222222",
+      "cursor_color": "#c2b790",
+      "foreground_color": "#c2b790",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Red Sands",
+      "palette": "#000000:#ff3f00:#00bb00:#e7b000:#0072ff:#bb00bb:#00bbbb:#bbbbbb:#555555:#bb0000:#00bb00:#e7b000:#0072ae:#ff55ff:#55ffff:#ffffff",
+      "background_color": "#7a251e",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#d7c9a7",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Relaxed",
+      "palette": "#151515:#bc5653:#909d63:#ebc17a:#6a8799:#b06698:#c9dfff:#d9d9d9:#636363:#bc5653:#a0ac77:#ebc17a:#7eaac7:#b06698:#acbbd0:#f7f7f7",
+      "background_color": "#353a44",
+      "cursor_color": "#d9d9d9",
+      "foreground_color": "#d9d9d9",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Rippedcasts",
+      "palette": "#000000:#cdaf95:#a8ff60:#bfbb1f:#75a5b0:#ff73fd:#5a647e:#bfbfbf:#666666:#eecbad:#bcee68:#e5e500:#86bdc9:#e500e5:#8c9bc4:#e5e5e5",
+      "background_color": "#2b2b2b",
+      "cursor_color": "#7f7f7f",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Royal",
+      "palette": "#241f2b:#91284c:#23801c:#b49d27:#6580b0:#674d96:#8aaabe:#524966:#312d3d:#d5356c:#2cd946:#fde83b:#90baf9:#a479e3:#acd4eb:#9e8cbd",
+      "background_color": "#100815",
+      "cursor_color": "#524966",
+      "foreground_color": "#514968",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Ryuuko",
+      "palette": "#2c3941:#865f5b:#66907d:#b1a990:#6a8e95:#b18a73:#88b2ac:#ececec:#5d7079:#865f5b:#66907d:#b1a990:#6a8e95:#b18a73:#88b2ac:#ececec",
+      "background_color": "#2c3941",
+      "cursor_color": "#ececec",
+      "foreground_color": "#ececec",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Seafoam Pastel",
+      "palette": "#757575:#825d4d:#728c62:#ada16d:#4d7b82:#8a7267:#729494:#e0e0e0:#8a8a8a:#cf937a:#98d9aa:#fae79d:#7ac3cf:#d6b2a1:#ade0e0:#e0e0e0",
+      "background_color": "#243435",
+      "cursor_color": "#57647a",
+      "foreground_color": "#d4e7d4",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "SeaShells",
+      "palette": "#17384c:#d15123:#027c9b:#fca02f:#1e4950:#68d4f1:#50a3b5:#deb88d:#434b53:#d48678:#628d98:#fdd39f:#1bbcdd:#bbe3ee:#87acb4:#fee4ce",
+      "background_color": "#09141b",
+      "cursor_color": "#fca02f",
+      "foreground_color": "#deb88d",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Seti",
+      "palette": "#323232:#c22832:#8ec43d:#e0c64f:#43a5d5:#8b57b5:#8ec43d:#eeeeee:#323232:#c22832:#8ec43d:#e0c64f:#43a5d5:#8b57b5:#8ec43d:#ffffff",
+      "background_color": "#111213",
+      "cursor_color": "#e3bf21",
+      "foreground_color": "#cacecd",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Shaman",
+      "palette": "#012026:#b2302d:#00a941:#5e8baa:#449a86:#00599d:#5d7e19:#405555:#384451:#ff4242:#2aea5e:#8ed4fd:#61d5ba:#1298ff:#98d028:#58fbd6",
+      "background_color": "#001015",
+      "cursor_color": "#4afcd6",
+      "foreground_color": "#405555",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Shel",
+      "background_color": "#2a201f",
+      "background_image": "None",
+      "cursor_color": "#6192d2",
+      "foreground_color": "#4882cd",
+      "palette": "#2c2423:#ab2463:#6ca323:#ab6423:#2c64a2:#6c24a2:#2ca363:#918988:#918988:#f588b9:#c2ee86:#f5ba86:#8fbaec:#c288ec:#8feeb9:#f5eeec",
+      "type": "dark"
+    },
+    {
+      "name": "Slate",
+      "palette": "#222222:#e2a8bf:#81d778:#c4c9c0:#264b49:#a481d3:#15ab9c:#02c5e0:#ffffff:#ffcdd9:#beffa8:#d0ccca:#7ab0d2:#c5a7d9:#8cdfe0:#e0e0e0",
+      "background_color": "#222222",
+      "cursor_color": "#87d3c4",
+      "foreground_color": "#35b1d2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Smyck",
+      "palette": "#000000:#b84131:#7da900:#c4a500:#62a3c4:#ba8acc:#207383:#a1a1a1:#7a7a7a:#d6837c:#c4f137:#fee14d:#8dcff0:#f79aff:#6ad9cf:#f7f7f7",
+      "background_color": "#1b1b1b",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#f7f7f7",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Snazzy",
+      "background_color": "#242424",
+      "background_image": "None",
+      "cursor_color": "#97979b",
+      "foreground_color": "#eff0eb",
+      "palette": "#282a36:#ff5c57:#5af78e:#f3f99d:#57c7ff:#ff6ac1:#9aedfe:#f1f1f0:#686868:#ff5c57:#5af78e:#f3f99d:#57c7ff:#ff6ac1:#9aedfe:#eff0eb",
+      "type": "dark"
+    },
+    {
+      "name": "SoftServer",
+      "palette": "#000000:#a2686a:#9aa56a:#a3906a:#6b8fa3:#6a71a3:#6ba58f:#99a3a2:#666c6c:#dd5c60:#bfdf55:#deb360:#62b1df:#606edf:#64e39c:#d2e0de",
+      "background_color": "#242626",
+      "cursor_color": "#d2e0de",
+      "foreground_color": "#99a3a2",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Solarized Darcula",
+      "palette": "#25292a:#f24840:#629655:#b68800:#2075c7:#797fd4:#15968d:#d2d8d9:#25292a:#f24840:#629655:#b68800:#2075c7:#797fd4:#15968d:#d2d8d9",
+      "background_color": "#3d3f41",
+      "cursor_color": "#708284",
+      "foreground_color": "#d2d8d9",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Solarized Dark",
+      "palette": "#002831:#d11c24:#738a05:#a57706:#2176c7:#c61c6f:#259286:#eae3cb:#001e27:#bd3613:#475b62:#536870:#708284:#5956ba:#819090:#fcf4dc",
+      "background_color": "#001e27",
+      "cursor_color": "#708284",
+      "foreground_color": "#708284",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Solarized Dark - Patched",
+      "palette": "#002831:#d11c24:#738a05:#a57706:#2176c7:#c61c6f:#259286:#eae3cb:#475b62:#bd3613:#475b62:#536870:#708284:#5956ba:#819090:#fcf4dc",
+      "background_color": "#001e27",
+      "cursor_color": "#708284",
+      "foreground_color": "#708284",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Solarized Dark Higher Contrast",
+      "palette": "#002831:#d11c24:#6cbe6c:#a57706:#2176c7:#c61c6f:#259286:#eae3cb:#006488:#f5163b:#51ef84:#b27e28:#178ec8:#e24d8e:#00b39e:#fcf4dc",
+      "background_color": "#001e27",
+      "cursor_color": "#f34b00",
+      "foreground_color": "#9cc2c3",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Solarized Light",
+      "palette": "#002831:#d11c24:#738a05:#a57706:#2176c7:#c61c6f:#259286:#eae3cb:#001e27:#bd3613:#475b62:#536870:#708284:#5956ba:#819090:#fcf4dc",
+      "background_color": "#fcf4dc",
+      "cursor_color": "#536870",
+      "foreground_color": "#536870",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Spacedust",
+      "palette": "#6e5346:#e35b00:#5cab96:#e3cd7b:#0f548b:#e35b00:#06afc7:#f0f1ce:#684c31:#ff8a3a:#aecab8:#ffc878:#67a0ce:#ff8a3a:#83a7b4:#fefff1",
+      "background_color": "#0a1e24",
+      "cursor_color": "#708284",
+      "foreground_color": "#ecf0c1",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "SpaceGray",
+      "palette": "#000000:#b04b57:#87b379:#e5c179:#7d8fa4:#a47996:#85a7a5:#b3b8c3:#000000:#b04b57:#87b379:#e5c179:#7d8fa4:#a47996:#85a7a5:#ffffff",
+      "background_color": "#20242d",
+      "cursor_color": "#b3b8c3",
+      "foreground_color": "#b3b8c3",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "SpaceGray Eighties",
+      "palette": "#15171c:#ec5f67:#81a764:#fec254:#5486c0:#bf83c1:#57c2c1:#efece7:#555555:#ff6973:#93d493:#ffd256:#4d84d1:#ff55ff:#83e9e4:#ffffff",
+      "background_color": "#222222",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#bdbaae",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "SpaceGray Eighties Dull",
+      "palette": "#15171c:#b24a56:#92b477:#c6735a:#7c8fa5:#a5789e:#80cdcb:#b3b8c3:#555555:#ec5f67:#89e986:#fec254:#5486c0:#bf83c1:#58c2c1:#ffffff",
+      "background_color": "#222222",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#c9c6bc",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Spiderman",
+      "palette": "#1b1d1e:#e60813:#e22928:#e24756:#2c3fff:#2435db:#3256ff:#fffef6:#505354:#ff0325:#ff3338:#fe3a35:#1d50ff:#747cff:#6184ff:#fffff9",
+      "background_color": "#1b1d1e",
+      "cursor_color": "#2c3fff",
+      "foreground_color": "#e3e3e3",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Spring",
+      "palette": "#000000:#ff4d83:#1f8c3b:#1fc95b:#1dd3ee:#8959a8:#3e999f:#ffffff:#000000:#ff0021:#1fc231:#d5b807:#15a9fd:#8959a8:#3e999f:#ffffff",
+      "background_color": "#ffffff",
+      "cursor_color": "#4d4d4c",
+      "foreground_color": "#4d4d4c",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Square",
+      "palette": "#050505:#e9897c:#b6377d:#ecebbe:#a9cdeb:#75507b:#c9caec:#f2f2f2:#141414:#f99286:#c3f786:#fcfbcc:#b6defb:#ad7fa8:#d7d9fc:#e2e2e2",
+      "background_color": "#1a1a1a",
+      "cursor_color": "#fcfbcc",
+      "foreground_color": "#acacab",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Sundried",
+      "palette": "#302b2a:#a7463d:#587744:#9d602a:#485b98:#864651:#9c814f:#c9c9c9:#4d4e48:#aa000c:#128c21:#fc6a21:#7999f7:#fd8aa1:#fad484:#ffffff",
+      "background_color": "#1a1818",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#c9c9c9",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Symfonic",
+      "palette": "#000000:#dc322f:#56db3a:#ff8400:#0084d4:#b729d9:#ccccff:#ffffff:#1b1d21:#dc322f:#56db3a:#ff8400:#0084d4:#b729d9:#ccccff:#ffffff",
+      "background_color": "#000000",
+      "cursor_color": "#dc322f",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Teerb",
+      "palette": "#1c1c1c:#d68686:#aed686:#d7af87:#86aed6:#d6aed6:#8adbb4:#d0d0d0:#1c1c1c:#d68686:#aed686:#e4c9af:#86aed6:#d6aed6:#b1e7dd:#efefef",
+      "background_color": "#262626",
+      "cursor_color": "#e4c9af",
+      "foreground_color": "#d0d0d0",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Terminal Basic",
+      "palette": "#000000:#990000:#00a600:#999900:#0000b2:#b200b2:#00a6b2:#bfbfbf:#666666:#e50000:#00d900:#e5e500:#0000ff:#e500e5:#00e5e5:#e5e5e5",
+      "background_color": "#ffffff",
+      "cursor_color": "#7f7f7f",
+      "foreground_color": "#000000",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Thayer Bright",
+      "palette": "#1b1d1e:#f92672:#4df840:#f4fd22:#2757d6:#8c54fe:#38c8b5:#ccccc6:#505354:#ff5995:#b6e354:#feed6c:#3f78ff:#9e6ffe:#23cfd5:#f8f8f2",
+      "background_color": "#1b1d1e",
+      "cursor_color": "#fc971f",
+      "foreground_color": "#f8f8f8",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "The Hulk",
+      "palette": "#1b1d1e:#269d1b:#13ce30:#63e457:#2525f5:#641f74:#378ca9:#d9d8d1:#505354:#8dff2a:#48ff77:#3afe16:#506b95:#72589d:#4085a6:#e5e6e1",
+      "background_color": "#1b1d1e",
+      "cursor_color": "#16b61b",
+      "foreground_color": "#b5b5b5",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Tomorrow",
+      "palette": "#000000:#c82829:#718c00:#eab700:#4271ae:#8959a8:#3e999f:#ffffff:#000000:#c82829:#718c00:#eab700:#4271ae:#8959a8:#3e999f:#ffffff",
+      "background_color": "#ffffff",
+      "cursor_color": "#4d4d4c",
+      "foreground_color": "#4d4d4c",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "Tomorrow Night",
+      "palette": "#000000:#cc6666:#b5bd68:#f0c674:#81a2be:#b294bb:#8abeb7:#ffffff:#000000:#cc6666:#b5bd68:#f0c674:#81a2be:#b294bb:#8abeb7:#ffffff",
+      "background_color": "#1d1f21",
+      "cursor_color": "#c5c8c6",
+      "foreground_color": "#c5c8c6",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Tomorrow Night Blue",
+      "palette": "#000000:#ff9da4:#d1f1a9:#ffeead:#bbdaff:#ebbbff:#99ffff:#ffffff:#000000:#ff9da4:#d1f1a9:#ffeead:#bbdaff:#ebbbff:#99ffff:#ffffff",
+      "background_color": "#002451",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Tomorrow Night Bright",
+      "palette": "#000000:#d54e53:#b9ca4a:#e7c547:#7aa6da:#c397d8:#70c0b1:#ffffff:#000000:#d54e53:#b9ca4a:#e7c547:#7aa6da:#c397d8:#70c0b1:#ffffff",
+      "background_color": "#000000",
+      "cursor_color": "#eaeaea",
+      "foreground_color": "#eaeaea",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Tomorrow Night Eighties",
+      "palette": "#000000:#f2777a:#99cc99:#ffcc66:#6699cc:#cc99cc:#66cccc:#ffffff:#000000:#f2777a:#99cc99:#ffcc66:#6699cc:#cc99cc:#66cccc:#ffffff",
+      "background_color": "#2d2d2d",
+      "cursor_color": "#cccccc",
+      "foreground_color": "#cccccc",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "ToyChest",
+      "palette": "#2c3f58:#be2d26:#1a9172:#db8e27:#325d96:#8a5edc:#35a08f:#23d183:#336889:#dd5944:#31d07b:#e7d84b:#34a6da:#ae6bdc:#42c3ae:#d5d5d5",
+      "background_color": "#24364b",
+      "cursor_color": "#d5d5d5",
+      "foreground_color": "#31d07b",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Treehouse",
+      "palette": "#321300:#b2270e:#44a900:#aa820c:#58859a:#97363d:#b25a1e:#786b53:#433626:#ed5d20:#55f238:#f2b732:#85cfed:#e14c5a:#f07d14:#ffc800",
+      "background_color": "#191919",
+      "cursor_color": "#fac814",
+      "foreground_color": "#786b53",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Twilight",
+      "palette": "#141414:#c06d44:#afb97a:#c2a86c:#44474a:#b4be7c:#778385:#ffffd4:#262626:#de7c4c:#ccd88c:#e2c47e:#5a5e62:#d0dc8e:#8a989b:#ffffd4",
+      "background_color": "#141414",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#ffffd4",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Ubuntu",
+      "palette": "#2e3436:#cc0000:#4e9a06:#c4a000:#3465a4:#75507b:#06989a:#d3d7cf:#555753:#ef2929:#8ae234:#fce94f:#729fcf:#ad7fa8:#34e2e2:#eeeeec",
+      "background_color": "#300a24",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#eeeeec",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "UnderTheSea",
+      "palette": "#022026:#b2302d:#00a941:#59819c:#459a86:#00599d:#5d7e19:#405555:#384451:#ff4242:#2aea5e:#8ed4fd:#61d5ba:#1298ff:#98d028:#58fbd6",
+      "background_color": "#011116",
+      "cursor_color": "#4afcd6",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Urple",
+      "palette": "#000000:#b0425b:#37a415:#ad5c42:#564d9b:#6c3ca1:#808080:#87799c:#5d3225:#ff6388:#29e620:#f08161:#867aed:#a05eee:#eaeaea:#bfa3ff",
+      "background_color": "#1b1b23",
+      "cursor_color": "#a063eb",
+      "foreground_color": "#877a9b",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Vag",
+      "background_color": "#191f1d",
+      "background_image": "None",
+      "cursor_color": "#e5f0fa",
+      "foreground_color": "#d9e6f2",
+      "palette": "#303030:#a87139:#39a871:#71a839:#7139a8:#a83971:#3971a8:#8a8a8a:#494949:#b0763b:#3bb076:#76b03b:#763bb0:#b03b76:#3b76b0:#cfcfcf",
+      "type": "dark"
+    },
+    {
+      "name": "Vaughn",
+      "palette": "#25234f:#705050:#60b48a:#dfaf8f:#5555ff:#f08cc3:#8cd0d3:#709080:#709080:#dca3a3:#60b48a:#f0dfaf:#5555ff:#ec93d3:#93e0e3:#ffffff",
+      "background_color": "#25234f",
+      "cursor_color": "#ff5555",
+      "foreground_color": "#dcdccc",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Venom",
+      "background_color": "#060d14",
+      "cursor_color": "#9ecfa2",
+      "foreground_color": "#668198",
+      "palette": "#2e3436:#e94759:#9ecfa2:#f3efa9:#00898d:#9c21b0:#06989a:#d3d7cf:#555753:#ef2929:#8ae234:#fce94f:#729fcf:#ad7fa8:#34e2e2:#eeeeec",
+      "type": "dark"
+    },
+    {
+      "name": "VibrantInk",
+      "palette": "#878787:#ff6600:#ccff04:#ffcc00:#44b4cc:#9933cc:#44b4cc:#f5f5f5:#555555:#ff0000:#00ff00:#ffff00:#0000ff:#ff00ff:#00ffff:#e5e5e5",
+      "background_color": "#000000",
+      "cursor_color": "#ffffff",
+      "foreground_color": "#ffffff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Violet Dark",
+      "palette": "#56595c:#c94c22:#85981c:#b4881d:#2e8bce:#d13a82:#32a198:#c9c6bd:#45484b:#bd3613:#738a04:#a57705:#2176c7:#c61c6f:#259286:#c9c6bd",
+      "background_color": "#1c1d1f",
+      "cursor_color": "#708284",
+      "foreground_color": "#708284",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Violet Light",
+      "palette": "#56595c:#c94c22:#85981c:#b4881d:#2e8bce:#d13a82:#32a198:#d3d0c9:#45484b:#bd3613:#738a04:#a57705:#2176c7:#c61c6f:#259286:#c9c6bd",
+      "background_color": "#fcf4dc",
+      "cursor_color": "#536870",
+      "foreground_color": "#536870",
+      "background_image": "None",
+      "type": "light"
+    },
+    {
+      "name": "WarmNeon",
+      "palette": "#000000:#e24346:#39b13a:#dae145:#4261c5:#f920fb:#2abbd4:#d0b8a3:#fefcfc:#e97071:#9cc090:#ddda7a:#7b91d6:#f674ba:#5ed1e5:#d8c8bb",
+      "background_color": "#404040",
+      "cursor_color": "#30ff24",
+      "foreground_color": "#afdab6",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Wez",
+      "palette": "#000000:#cc5555:#55cc55:#cdcd55:#5555cc:#cc55cc:#7acaca:#cccccc:#555555:#ff5555:#55ff55:#ffff55:#5555ff:#ff55ff:#55ffff:#ffffff",
+      "background_color": "#000000",
+      "cursor_color": "#53ae71",
+      "foreground_color": "#b3b3b3",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "WildCherry",
+      "palette": "#000507:#d94085:#2ab250:#ffd16f:#883cdc:#ececec:#c1b8b7:#fff8de:#009cc9:#da6bac:#f4dca5:#eac066:#308cba:#ae636b:#ff919d:#e4838d",
+      "background_color": "#1f1726",
+      "cursor_color": "#dd00ff",
+      "foreground_color": "#dafaff",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Wombat",
+      "palette": "#000000:#ff615a:#b1e969:#ebd99c:#5da9f6:#e86aff:#82fff7:#dedacf:#313131:#f58c80:#ddf88f:#eee5b2:#a5c7ff:#ddaaff:#b7fff9:#ffffff",
+      "background_color": "#171717",
+      "cursor_color": "#bbbbbb",
+      "foreground_color": "#dedacf",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Wryan",
+      "palette": "#333333:#8c4665:#287373:#7c7c99:#395573:#5e468c:#31658c:#899ca1:#3d3d3d:#bf4d80:#53a6a6:#9e9ecb:#477ab3:#7e62b3:#6096bf:#c0c0c0",
+      "background_color": "#101010",
+      "cursor_color": "#9e9ecb",
+      "foreground_color": "#999993",
+      "background_image": "None",
+      "type": "dark"
+    },
+    {
+      "name": "Zenburn",
+      "palette": "#4d4d4d:#705050:#60b48a:#f0dfaf:#506070:#dc8cc3:#8cd0d3:#dcdccc:#709080:#dca3a3:#c3bf9f:#e0cf9f:#94bff3:#ec93d3:#93e0e3:#ffffff",
+      "background_color": "#3f3f3f",
+      "cursor_color": "#73635a",
+      "foreground_color": "#dcdccc",
+      "background_image": "None",
+      "type": "dark"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/emacs/.emacs.d/wpc/terminator.el b/emacs/.emacs.d/wpc/terminator.el
new file mode 100644
index 000000000000..4794ce2d90a3
--- /dev/null
+++ b/emacs/.emacs.d/wpc/terminator.el
@@ -0,0 +1,94 @@
+;;; terminator.el --- Experimenting with theming Terminator -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; I think most of this module is me getting carried away with the idea of
+;; theming Terminator.  Terminator themes are defined in a themes.json file.  As
+;; far as I know, Terminator does not support specifying these themes by name on
+;; the command line, which would greatly simplify things.  Terminator does
+;; support passing a --profile flag, however, which can be used to specify the
+;; themes.  The idea, albeit quite awkward and over-engineered, was to create
+;; these profile files on the fly and pass them to terminator.  After around 45
+;; minutes of tinkering with this, the idea is starting to disenchant me.
+;;
+;; Alternative solutions include:
+;; 1. Further investigating what other options Terminator supports.
+;; 2. Using a different terminal emulator.
+;; 3. Just right clicking Terminator and changing the themes manually.
+
+;;; Code:
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'alist)
+(require 'string)
+(require 'json)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defstruct terminator/theme
+  foreground-color
+  background-color
+  cursor-color
+  palette)
+
+(defvar terminator/palettes
+  '((solarized-light . "#002831:#d11c24:#738a05:#a57706:#2176c7:#c61c6f:#259286:#eae3cb:#001e27:#bd3613:#475b62:#536870:#708284:#5956ba:#819090:#fcf4dc"))
+  "Mapping of theme names to the color palette that terminator expects.")
+
+(defconst terminator/profile-template "[global_config]
+  enabled_plugins = LaunchpadBugURLHandler, LaunchpadCodeURLHandler, APTURLHandler, TerminatorThemes
+[keybindings]
+[profiles]
+  [[default]]
+    background_color = \"%s\"
+    cursor_shape = ibeam
+    cursor_color = \"%s\"
+    font = Input Mono Medium 12
+    foreground_color = \"%s\"
+    show_titlebar = False
+    scrollbar_position = hidden
+    palette = \"%s\"
+    use_system_font = False
+[layouts]
+  [[default]]
+    [[[child1]]]
+      parent = window0
+      type = Terminal
+      profile = Molokai
+    [[[window0]]]
+      parent = \"\"
+      type = Window
+[plugins]"
+  "Template string of a terminator profile file.")
+
+(cl-defun terminator/render-profile (&key foreground-color
+                                          background-color
+                                          cursor-color
+                                          palette)
+  "Create a terminator profile with THEME as the palette."
+  (string/format terminator/profile-template
+                 background-color
+                 cursor-color
+                 foreground-color
+                 palette))
+
+(defun terminator/as-heredoc (x)
+  "Return an EOF-terminator heredoc of X."
+  (string/format "<<EOF\n%s\nEOF" x))
+
+(prelude/start-process
+ :name "termination"
+ :command (string/format "zsh -c terminator --profile=%s"
+                         (->> 'solarized-light
+                              terminator/render-profile
+                              terminator/as-heredoc)))
+(string/format terminator/profile-template
+               (alist/get 'solarized-light terminator/palettes))
+
+(provide 'terminator)
+;;; terminator.el ends here
diff --git a/emacs/.emacs.d/wpc/themes.el b/emacs/.emacs.d/wpc/themes.el
new file mode 100644
index 000000000000..ee81d3beed72
--- /dev/null
+++ b/emacs/.emacs.d/wpc/themes.el
@@ -0,0 +1,204 @@
+;;; themes.el --- Functions for working with my themes. -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+
+
+;; Because I couldn't get cycle-themes to work, I'm writing my own version.
+;;
+;; Terminology:
+;; - colorscheme: determines the colors used by syntax highlighting and other
+;;   Emacs UI elements.
+;; - theme: Structural representation of a "theme" that includes colorscheme
+;;   (see above), font, wallpaper.  "theme" is a superset of "colorscheme".
+;;
+;; Wishlist:
+;; - TODO: Find a way to update the terminal (e.g. terminator) theme.
+;; - TODO: Ensure terminal font is updated when Emacs font changes.
+;; - TODO: Support a light theme.
+;; - TODO: Support Rick & Morty theme.
+;; - TODO: Support retro/arcade/80s theme.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'alist)
+(require 'symbol)
+(require 'f)
+(require 'wallpaper)
+(require 'fonts)
+(require 'cycle)
+(require 'symbol)
+(require 'random)
+(require 'colorscheme)
+(require 'dotted)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; The theme struct couples a font, a wallpaper, and a colorschemes.
+(cl-defstruct theme
+  font
+  wallpaper
+  colorscheme)
+
+(defvar themes/current nil
+  "Store the name of the currently enabled theme.")
+
+(defconst themes/themes
+  (list (dotted/new
+         "Forest"
+         (make-theme
+          :font "Operator Mono Light"
+          :wallpaper "forest_8k.jpg"
+          :colorscheme 'doom-peacock))
+        (dotted/new
+         "Geometry"
+         (make-theme
+          :font "Input Mono Medium"
+          :wallpaper "geometric_4k.jpg"
+          :colorscheme 'doom-molokai))
+        (dotted/new
+         "Ice"
+         (make-theme
+          :font "Go Mono"
+          :wallpaper "construction_paper_iceberg_4k.jpg"
+          :colorscheme 'doom-dracula))
+        (dotted/new
+         "Lego Manhattan"
+         (make-theme
+          :font "Input Mono Medium"
+          :wallpaper "lego_manhattan.jpg"
+          :colorscheme 'base16-atelier-sulphurpool))
+        (dotted/new
+         "Shapely Patterns"
+         (make-theme
+          :font "Operator Mono Light"
+          :wallpaper "geometric_dark_4k.jpg"
+          :colorscheme 'doom-vibrant))
+        ;; TODO: Support setting backgrounds as solid colors.
+        (dotted/new
+         "Gruvbox"
+         (make-theme
+          :font "JetBrainsMono"
+          :wallpaper "geometric_dark_4k.jpg"
+          :colorscheme 'doom-gruvbox))
+        (dotted/new
+         "Solarized Light"
+         (make-theme
+          :font "JetBrainsMono"
+          :wallpaper "solarized_light_thinkpad.jpg"
+          :colorscheme 'doom-solarized-light))
+        (dotted/new
+         "Lightness"
+         (make-theme
+          :font "Input Mono Medium"
+          :wallpaper "construction_paper_iceberg_4k.jpg"
+          :colorscheme 'doom-one-light))
+        (dotted/new
+         "Edison Lightbulb"
+         (make-theme
+          :font "Mononoki Medium"
+          :wallpaper "lightbulb_4k.jpg"
+          :colorscheme 'base16-atelier-cave))
+        (dotted/new
+         "Wall-E"
+         (make-theme
+          :font "Input Mono Medium"
+          :wallpaper "walle_4k.jpg"
+          :colorscheme 'doom-material))
+        (dotted/new
+         "Galaxy"
+         (make-theme
+          :font "Source Code Pro"
+          :wallpaper "galaxy_4k.jpg"
+          :colorscheme 'doom-moonlight))
+        (dotted/new
+         "Underwater"
+         (make-theme
+          :font "Go Mono"
+          ;; TODO: Change this wallpaper to an oceanic scene.
+          :wallpaper "galaxy_4k.jpg"
+          :colorscheme 'doom-solarized-dark))
+        (dotted/new
+         "Fantasy Tree"
+         (make-theme
+          :font "Go Mono"
+          :wallpaper "fantasy_tree_4k.jpg"
+          :colorscheme 'doom-outrun-electric)))
+  "Predefined themes to suit my whims.")
+
+;; TODO: Choose between plural and singular names for Elisp modules.  For
+;; example, why have themes.el and colorscheme.el.  I think singular is
+;; preferable.
+;; TODO: Decide between "message", "show", "print", "inspect" for naming
+;; commands that output human-readable information to the "*Messages*" buffer.
+;; TODO: Is there a idiomatic CL/Elisp way to print struct information?
+(defun themes/print (name)
+  "Print a human-readable description of theme named NAME."
+  (let* ((theme (alist/get name themes/themes))
+         (f (theme-font theme))
+         (w (theme-wallpaper theme))
+         (c (theme-colorscheme theme)))
+    (message (string/format
+              "[themes] Name: %s. Font: %s. Wallpaper: %s. Colorscheme: %s"
+              name f w c))))
+
+;; TODO: Make this into a proper test.
+(defun themes/debug ()
+  "Print a human-readable description of theme named NAME."
+  (interactive)
+  (let ((theme (alist/get themes/current themes/themes)))
+    (prelude/assert (equal (theme-font theme)
+                           (fonts/current)))
+    (prelude/assert (equal (theme-wallpaper theme)
+                           (f-filename (wallpaper/current))))
+    (prelude/assert (equal (theme-colorscheme theme)
+                           (colorscheme/current)))
+    (message "[themes] Debug couldn't find any inconsistencies. All good!")))
+
+;; TODO: Assert that all of the dependencies exist before attempting to load
+;; theme.
+;; TODO: Provide a friendlier way to define themes.
+(defun themes/ivy-select ()
+  "Use ivy to interactively load a theme."
+  (interactive)
+  (let* ((name (ivy-read "Theme: " (alist/keys themes/themes))))
+    (message (string/format "name: %s" name))
+    (themes/set name)))
+
+(defun themes/load (theme)
+  "Load the struct, THEME."
+  (colorscheme/disable-all)
+  (let* ((font (theme-font theme))
+         (wallpaper (theme-wallpaper theme))
+         (colorscheme (theme-colorscheme theme)))
+    (fonts/whitelist-set font)
+    (wallpaper/whitelist-set (f-join wallpaper/path-to-dir wallpaper))
+    (colorscheme/whitelist-set colorscheme)))
+
+(defun themes/set (name)
+  "Set the currently enabled theme to the theme named NAME.
+NAME needs to a key defined in `themes/themes'."
+  (prelude/assert (alist/has-key? name themes/themes))
+  (themes/load (alist/get name themes/themes))
+  (setq themes/current name))
+
+(defun themes/print-current ()
+  "Print the currently enabled theme."
+  (interactive)
+  (themes/print themes/current))
+
+(defun themes/random ()
+  "Return the name of a randomly selected theme in `themes/themes'."
+  (->> themes/themes
+       alist/keys
+       random/choice))
+
+(provide 'themes)
+;;; themes.el ends here
diff --git a/emacs/.emacs.d/wpc/todo.el b/emacs/.emacs.d/wpc/todo.el
new file mode 100644
index 000000000000..236912c086fd
--- /dev/null
+++ b/emacs/.emacs.d/wpc/todo.el
@@ -0,0 +1,293 @@
+;;; todo.el --- Bespoke task management system -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Marriage of my personal task-management system, which I've been using for 18
+;; months and is a mixture of handwritten notes, iOS notes, and org-mode files,
+;; with Emacs's famous `org-mode'.
+;;
+;; For me, I'd like a live, reactive state management system.  I'd like
+;; `org-mode' to be a nice way of rendering my TODOs, but I think the
+;; relationship with `org-mode' ends there.
+;;
+;; Intended to supplement my org-mode workflow.
+;;
+;; Wish-list:
+;; - Daily emails for standups
+;; - Templates for commonly occurring tasks
+
+;; Dependencies
+(require 'dash)
+(require 'f)
+(require 'macros)
+
+;;; Code:
+
+;; TODO: Classify habits as 'daily, 'weekly, 'monthly, 'yearly, 'event-driven
+
+;; TODO: Consider serving these values up to a React webpage in Chrome.
+
+;; TODO: Classify meetings as either 'recurrent or 'ad-hoc.
+
+;; TODO: Support sorting by `type'.
+
+;; TODO: Support work-queue idea for "Tomorrow's todos."
+
+;; TODO: Support macro to generate all possible predicates for todo types.
+
+;; TODO: Support export to org-mode file
+
+;; TODO: Support generic way to quickly render a list
+
+(defcustom todo/install-kbds? t
+  "When t, install the keybindings.")
+
+;; TODO: Add documentation.
+(cl-defstruct todo type label)
+
+;; TODO: Consider keeping this in Dropbox.
+;; TODO: Support whether or not the todo is done.
+(defconst todo/org-file-path "~/Dropbox/org/today.org")
+
+;; TODO: Support remaining function for each type.
+;; TODO: Support completed function for each type.
+
+(defun todo/completed? (x)
+  "Return t is `X' is marked complete."
+  (todo-complete x))
+
+;; TODO: Prefer `new-{task,habit,meeting}'.
+
+(defun todo/completed (xs)
+  "Return the todo items in `XS' that are marked complete."
+  (->> xs
+       (-filter #'todo/completed?)))
+
+(defun todo/remaining (xs)
+  "Return the todo items in `XS' that are not marked complete."
+  (->> xs
+       (-reject #'todo/completed?)))
+
+(defun todo/task (label)
+  "Convenience function for creating a task todo with `LABEL'."
+  (make-todo
+   :type 'task
+   :label label))
+
+(defun todo/meeting (label)
+  "Convenience function for creating a meeting todo with `LABEL'."
+  (make-todo
+   :type 'meeting
+   :label label))
+
+(defun todo/habit (label)
+  "Convenience function for creating a habit todo with `LABEL'."
+  (make-todo
+   :type 'habit
+   :label label))
+
+(defun todo/task? (x)
+  "Return t if `X' is a task."
+  (equal 'task (todo-type x)))
+
+(defun todo/habit? (x)
+  "Return t if `X' is a habit."
+  (equal 'habit (todo-type x)))
+
+(defun todo/meeting? (x)
+  "Return t if `X' is a meeting."
+  (equal 'meeting (todo-type x)))
+
+(defun todo/label (x)
+  "Return the label of `X'."
+  (todo-label x))
+
+;; TODO: Support moving todos between todo/{today,tomorrow}.
+;; TODO: Consider modelling todo/{today,tomorrow} as queues instead of lists so that I can
+;; append cheaply.
+
+;; TODO: Find an Elisp date library.
+
+;; TODO: type-driven development of this habit tree.
+;; TODO: Create this tree on a whiteboard first.
+;; (defconst todo/habits
+;;   '(:beginning-of-month
+;;     '("Create habit template for current month"
+;;       "Post mortem of previous month")
+;;     :monday    '("Jiu Jitsu")
+;;     :tuesday   '("Jiu Jitsu")
+;;     :wednesday '("Jiu Jitsu")
+;;     :thursday  '("Salsa class")
+;;     :friday    '("Jiu Jitsu")
+;;     :saturday  '("Borough market")
+;;     :sunday    '("Shave")
+;;     :weekday '(:arrive-at-work
+;;                '("Breakfast"
+;;                  "Coffee"
+;;                  "Placeholder")
+;;                :before-lunch
+;;                '("Lock laptop"
+;;                  "Placeholder")
+;;                :home->work
+;;                '("Michel Thomas Italian lessons"))
+;;     :daily '(:morning
+;;              '("Meditate"
+;;                "Stretch")
+;;              :)))
+
+;; overlay weekday with specific weekdays (e.g. BJJ is only on M,T,W)
+
+;; TODO: Extend the record type to support duration estimations for AFK, K
+;; calculations.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Habits
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Should I be writing this in ReasonML and Haskell?
+
+(defconst todo/monthly-habit-challenge
+  "InterviewCake.com"
+  "The monthly habit challenge I do for fifteen minutes each day.")
+
+(defconst todo/daily-habits
+  (->> (list "Meditate"
+             todo/monthly-habit-challenge)
+       (-map #'todo/habit)))
+
+(defconst todo/first-of-the-month-stack
+  '("Create habit template for current month"
+    "Reserve two dinners in London for dates"
+    "Post mortem of previous month"
+    "Create monthly financial budget in Google Sheets")
+  "A stack of habits that I do at the beginning of each month.")
+
+(defconst todo/adhoc-habits
+  (->> (list/concat
+        todo/first-of-the-month-stack)
+       (-map #'todo/habit))
+  "Habits that I have no classification for at the moment.")
+
+;; TODO: Model this as a function.
+(defconst todo/habits
+  (list/concat todo/daily-habits
+               todo/adhoc-habits)
+  "My habits for today.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Meetings
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Define "meeting".
+
+(defconst todo/daily-meetings
+  (->> '("Standup"
+         "Lunch")
+       (-map #'todo/meeting))
+  "Daily, recurrent meetings.")
+
+
+(defconst todo/day-of-week-meetings
+  '(:Monday    '("Lunch")
+    :Tuesday   '("Lunch")
+    :Wednesday '("Team Lunch")
+    :Thursday  '("Lunch")
+    :Friday    '("Lunch")
+    :Satuday   '()
+    :Sunday    '())
+  "Meetings that occur depending on the current day of the week.")
+
+(parse-time-string "today")
+
+;; TODO: Support recurrent, non-daily meetings.
+
+(defconst todo/adhoc-meetings
+  (->> '("WSE Weekly Standup"
+         "Team Lunch"
+         "Karisa Explains It All")
+       (-map #'todo/meeting))
+  "Non-recurrent meetings.")
+
+(defconst todo/meetings
+  (list/concat todo/daily-meetings
+               todo/adhoc-meetings)
+  "My meetings for today.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tasks
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst todo/tasks
+  (->> '("GetEmailCase"
+         "Async node workflow"
+         "Support C-c in EXWM"
+         "Post-its for bathroom mirror"
+         "Visit AtomicHabit.com/scorecard"
+         "Visit AtomicHabit.com/habitstacking"
+         "Create GraphViz for Carpe Diem cirriculum"
+         "Create CitC client for local browsing of CE codebase"
+         "Respond to SRE emails")
+       (-map #'todo/task)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Work queues (today, tomorrow, someday)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Generate standup documents from DONE items in the state.
+
+;; TODO: Learn how to create a gen-server style of live, reactive state.
+;; TODO: This should probably be `defconst' and a reference to the live state.
+(defconst todo/today
+  (list/concat
+   todo/habits
+   todo/meetings
+   todo/tasks))
+
+(defconst todo/tomorrow
+  '())
+
+(defconst todo/someday
+  '())
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; View functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun todo/to-org (xs)
+  "Map `XS' into a string with `org-mode' syntax."
+  ;; TODO: Create function to DRY this code up.
+  (let ((meetings (->> xs
+                       (-filter #'todo/meeting?)
+                       (-map (lambda (x)
+                               (s-concat "** TODO " (todo/label x))))
+                       (s-join "\n")))
+        (tasks (->> xs
+                    (-filter #'todo/task?)
+                    (-map (lambda (x)
+                            (s-concat "** TODO " (todo/label x))))
+                    (s-join "\n")))
+        (habits (->> xs
+                     (-filter #'todo/habit?)
+                     (-map (lambda (x)
+                             (s-concat "** TODO " (todo/label x))))
+                     (s-join "\n"))))
+    (s-join "\n" (list
+                  (s-concat "* Meetings\n" meetings)
+                  (s-concat "* Tasks\n" tasks)
+                  (s-concat "* Habits\n" habits)))))
+
+(defun todo/export-to-org (xs)
+  "Export `XS' to `todo/org-file-path'."
+  (f-write-text (->> xs
+                     todo/to-org)
+                'utf-8
+                todo/org-file-path))
+
+(defun todo/orgify-today ()
+  "Exports today's todos to an org file."
+  (interactive)
+  (todo/export-to-org todo/today)
+  (alert (string/concat  "Exported today's TODOs to: " todo/org-file-path)))
+
+(provide 'todo)
+;;; todo.el ends here
diff --git a/emacs/.emacs.d/wpc/tree.el b/emacs/.emacs.d/wpc/tree.el
new file mode 100644
index 000000000000..43df4dc500e7
--- /dev/null
+++ b/emacs/.emacs.d/wpc/tree.el
@@ -0,0 +1,193 @@
+;;; tree.el --- Working with Trees -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Some friendly functions that hopefully will make working with trees cheaper
+;; and therefore more appealing!
+;;
+;; Tree terminology:
+;; - leaf: node with zero children.
+;; - root: node with zero parents.
+;; - depth: measures a node's distance from the root node.  This implies the
+;;   root node has a depth of zero.
+;; - height: measures the longest traversal from a node to a leaf.  This implies
+;;   that a leaf node has a height of zero.
+;; - balanced?
+;;
+;; Tree variants:
+;; - binary: the maximum number of children is two.
+;; - binary search: the maximum number of children is two and left sub-trees are
+;;   lower in value than right sub-trees.
+;; - rose: the number of children is variable.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'list)
+(require 'set)
+(require 'tuple)
+(require 'series)
+(require 'random)
+(require 'maybe)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(cl-defstruct tree xs)
+
+(cl-defstruct node value children)
+
+(cl-defun tree/node (value &optional children)
+  "Create a node struct of VALUE with CHILDREN."
+  (make-node :value value
+             :children children))
+
+(defun tree/reduce-breadth (acc f xs)
+  "Reduce over XS breadth-first applying F to each x and ACC (in that order).
+Breadth-first traversals guarantee to find the shortest path in a graph.
+  They're typically more difficult to implement than DFTs and may also incur
+  higher memory costs on average than their depth-first counterparts.")
+
+;; TODO: Support :order as 'pre | 'in | 'post.
+;; TODO: Troubleshoot why I need defensive (nil? node) check.
+(defun tree/reduce-depth (acc f node)
+  "Reduce over NODE depth-first applying F to each NODE and ACC.
+F is called with each NODE, ACC, and the current depth.
+Depth-first traversals have the advantage of typically consuming less memory
+  than their breadth-first equivalents would have.  They're also typically
+  easier to implement using recursion.  This comes at the cost of not
+  guaranteeing to be able to find the shortest path in a graph."
+  (cl-labels ((do-reduce-depth
+               (acc f node depth)
+               (let ((acc-new (funcall f node acc depth)))
+                 (if (or (maybe/nil? node)
+                         (tree/leaf? node))
+                     acc-new
+                   (list/reduce
+                    acc-new
+                    (lambda (node acc)
+                      (tree/do-reduce-depth
+                       acc
+                       f
+                       node
+                       (number/inc depth)))
+                    (node-children node))))))
+    (do-reduce-depth acc f node 0)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Helpers
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun tree/height (xs)
+  "Return the height of tree XS.")
+
+;; TODO: Troubleshoot why need for (nil? node).  Similar misgiving
+;; above.
+(defun tree/leaf-depths (xs)
+  "Return a list of all of the depths of the leaf nodes in XS."
+  (list/reverse
+   (tree/reduce-depth
+    '()
+    (lambda (node acc depth)
+      (if (or (maybe/nil? node)
+              (tree/leaf? node))
+          (list/cons depth acc)
+        acc))
+    xs)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Generators
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Consider parameterizing height, forced min-max branching, random
+;; distributions, etc.
+
+;; TODO: Bail out before stack overflowing by consider branching, current-depth.
+
+(cl-defun tree/random (&optional (value-fn (lambda (_) nil))
+                                 (branching-factor 2))
+  "Randomly generate a tree with BRANCHING-FACTOR using VALUE-FN to compute the
+node values.  VALUE-FN is called with the current-depth of the node.  Useful for
+generating test data.  Warning this function can overflow the stack."
+  (cl-labels ((do-random
+               (d vf bf)
+               (make-node
+                :value (funcall vf d)
+                :children (->> (series/range 0 (number/dec bf))
+                               (list/map
+                                (lambda (_)
+                                  (when (random/boolean?)
+                                    (do-random d vf bf))))))))
+    (do-random 0 value-fn branching-factor)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun tree/instance? (tree)
+  "Return t if TREE is a tree struct."
+  (node-p tree))
+
+(defun tree/leaf? (node)
+  "Return t if NODE has no children."
+  (maybe/nil? (node-children node)))
+
+(defun tree/balanced? (n xs)
+  "Return t if the tree, XS, is balanced.
+A tree is balanced if none of the differences between any two depths of two leaf
+  nodes in XS is greater than N."
+  (> n (->> xs
+            tree/leaf-depths
+            set/from-list
+            set/count
+            number/dec)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst tree/enable-testing? t
+  "When t, test suite runs.")
+
+;; TODO: Create set of macros for a proper test suite including:
+;; - describe (arbitrarily nestable)
+;; - it (arbitrarily nestable)
+;; - line numbers for errors
+;; - accumulated output for synopsis
+;; - do we want describe *and* it? Why not a generic label that works for both?
+(when tree/enable-testing?
+  (let ((tree-a (tree/node 1
+                           (list (tree/node 2
+                                            (list (tree/node 5)
+                                                  (tree/node 6)))
+                                 (tree/node 3
+                                            (list (tree/node 7)
+                                                  (tree/node 8)))
+                                 (tree/node 4
+                                            (list (tree/node 9)
+                                                  (tree/node 10))))))
+        (tree-b (tree/node 1
+                           (list (tree/node 2
+                                            (list (tree/node 5)
+                                                  (tree/node 6)))
+                                 (tree/node 3)
+                                 (tree/node 4
+                                            (list (tree/node 9)
+                                                  (tree/node 10)))))))
+    ;; instance?
+    (prelude/assert (tree/instance? tree-a))
+    (prelude/assert (tree/instance? tree-b))
+    (prelude/refute (tree/instance? '(1 2 3)))
+    (prelude/refute (tree/instance? "oak"))
+    ;; balanced?
+    (prelude/assert (tree/balanced? 1 tree-a))
+    (prelude/refute (tree/balanced? 1 tree-b))
+    (message "Tests pass!")))
+
+(provide 'tree)
+;;; tree.el ends here
diff --git a/emacs/.emacs.d/wpc/tuple.el b/emacs/.emacs.d/wpc/tuple.el
new file mode 100644
index 000000000000..ccebf7299abd
--- /dev/null
+++ b/emacs/.emacs.d/wpc/tuple.el
@@ -0,0 +1,86 @@
+;;; tuple.el --- Tuple API for Elisp -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Work with cons cells with two elements with a familiar API for those who have
+;; worked with tuples before.
+
+;;; Code:
+
+(cl-defstruct tuple first second)
+
+;; Create
+(defun tuple/new ()
+  "Return an empty tuple."
+  (make-tuple :first nil
+              :second nil))
+
+(defun tuple/from (a b)
+  "Return a new tuple from A and B."
+  (make-tuple :first a
+              :second b))
+
+(defun tuple/from-dotted (dp)
+  "Convert dotted pair, DP, into a tuple."
+  (tuple/from (car dp) (cdr dp)))
+
+;; Read
+(defun tuple/first (pair)
+  "Return the first element of PAIR."
+  (tuple-first pair))
+
+(defun tuple/second (pair)
+  "Return the second element of PAIR."
+  (tuple-second pair))
+
+;; Update
+(defun tuple/map-each (f g pair)
+  "Apply F to first, G to second in PAIR."
+  (->> pair
+       (tuple/map-first f)
+       (tuple/map-second g)))
+
+(defun tuple/map (f pair)
+  "Apply F to PAIR."
+  (let ((pair-copy (copy-tuple pair)))
+    (funcall f pair-copy)))
+
+(defun tuple/map-first (f pair)
+  "Apply function F to the first element of PAIR."
+  (let ((pair-copy (copy-tuple pair)))
+    (setf (tuple-first pair-copy) (funcall f (tuple/first pair-copy)))
+    pair-copy))
+
+(defun tuple/map-second (f pair)
+  "Apply function F to the second element of PAIR."
+  (let ((pair-copy (copy-tuple pair)))
+    (setf (tuple-second pair-copy) (funcall f (tuple/second pair-copy)))
+    pair-copy))
+
+(defun tuple/set-first (a pair)
+  "Return a new tuple with the first element set as A in PAIR."
+  (tuple/map-first (lambda (_) a) pair))
+
+(defun tuple/set-second (b pair)
+  "Return a new tuple with the second element set as B in PAIR."
+  (tuple/map-second (lambda (_) b) pair))
+
+;; Delete
+(defun tuple/delete-first (pair)
+  "Return PAIR with the first element set to nil."
+  (tuple/set-first nil pair))
+
+(defun tuple/delete-second (pair)
+  "Return PAIR with the second element set to nil."
+  (tuple/set-second nil pair))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun tuple/instance? (x)
+  "Return t if X is a tuple."
+  (tuple-p x))
+
+(provide 'tuple)
+;;; tuple.el ends here
diff --git a/emacs/.emacs.d/wpc/vector.el b/emacs/.emacs.d/wpc/vector.el
new file mode 100644
index 000000000000..6d2fe20d1209
--- /dev/null
+++ b/emacs/.emacs.d/wpc/vector.el
@@ -0,0 +1,81 @@
+;;; vector.el --- Working with Elisp's Vector data type -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; It might be best to think of Elisp vectors as tuples in languages like
+;; Haskell or Erlang.
+;;
+;; Not surprisingly, this API is modelled after Elixir's Tuple API.
+;;
+;; Some Elisp trivia:
+;; - "Array": Usually means vector or string.
+;; - "Sequence": Usually means list or "array" (see above).
+;;
+;; It might be a good idea to think of Array and Sequence as typeclasses in
+;; Elisp.  This is perhaps more similar to Elixir's notion of the Enum protocol.
+;;
+;; Intentionally not supporting a to-list function, because tuples can contain
+;; heterogenous types whereas lists should contain homogenous types.
+
+;;; Code:
+
+;; TODO: Consider supporting an alias named tuple for vector.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst vector/enable-tests? t
+  "When t, run the tests defined herein.")
+
+;; TODO: Consider labelling variadic functions like `vector/concat*'
+;; vs. `vector/concat'.
+(defun vector/concat (&rest args)
+  "Return a new vector composed of all vectors in `ARGS'."
+  (apply #'vconcat args))
+
+;; TODO: Here's a sketch of a protocol macro being consumed.
+;; (definstance monoid vector
+;;   :empty (lambda () []))
+
+(defun vector/prepend (x xs)
+  "Add `X' to the beginning of `XS'."
+  (vector/concat `[,x] xs))
+
+(defun vector/append (x xs)
+  "Add `X' to the end of `XS'."
+  (vector/concat xs `[,x]))
+
+(defun vector/get (i xs)
+  "Return the value in `XS' at index, `I'."
+  (aref xs i))
+
+(defun vector/set (i v xs)
+  "Set index `I' to value `V' in `XS'.
+Returns a copy of `XS' with the updates."
+  (let ((copy (vconcat [] xs)))
+    (aset copy i v)
+    copy))
+
+(defun vector/set! (i v xs)
+  "Set index `I' to value `V' in `XS'.
+This function mutates XS."
+  (aset xs i v))
+
+(when vector/enable-tests?
+  (let ((xs [1 2 3])
+        (ys [1 2 3]))
+    (prelude/assert (= 1 (vector/get 0 ys)))
+    (vector/set 0 4 ys)
+    (prelude/assert (= 1 (vector/get 0 ys)))
+    (prelude/assert (= 1 (vector/get 0 xs)))
+    (vector/set! 0 4 xs)
+    (prelude/assert (= 4 (vector/get 0 xs)))))
+
+;; TODO: Decide between "remove" and "delete" as the appropriate verbs.
+;; TODO: Implement this.
+;; (defun vector/delete (i xs)
+;;   "Remove the element at `I' in `XS'.")
+
+(provide 'vector)
+;;; vector.el ends here
diff --git a/emacs/.emacs.d/wpc/wallpaper.el b/emacs/.emacs.d/wpc/wallpaper.el
new file mode 100644
index 000000000000..9aa41cd364a4
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wallpaper.el
@@ -0,0 +1,92 @@
+;;; wallpaper.el --- Control Linux desktop wallpaper -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Functions for setting desktop wallpaper.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'fs)
+(require 'cycle)
+(require 'string)
+(require 'general)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defcustom wallpaper/keybindings? t
+  "If non-nil, install the keybindings.")
+
+(defcustom wallpaper/path-to-dir
+  (f-expand "~/.local/share/wallpaper")
+  "Path to the images that will be used as the wallpaper.")
+
+(defconst wallpaper/whitelist
+  (cycle/from-list
+   (fs/ls wallpaper/path-to-dir t))
+  "My preferred computer wallpapers.")
+
+(defun wallpaper/set (path)
+  "Set computer wallpaper to image at `PATH' using `feh` under-the-hood.
+`PATH' can be absolute or relative since `f-expand' is called in the function
+  body to ensure feh can resolve the path."
+  (prelude/start-process
+   :name "wallpaper/set"
+   :command (string/format "feh --bg-scale --no-feh-bg %s" (f-expand path))))
+
+(defun wallpaper/whitelist-set (wallpaper)
+  "Focuses the WALLPAPER in the `wallpaper/whitelist' cycle."
+  (cycle/focus (lambda (x) (equal x wallpaper)) wallpaper/whitelist)
+  (wallpaper/set (wallpaper/current)))
+
+(defun wallpaper/next ()
+  "Cycles to the next wallpaper."
+  (interactive)
+  (let ((wallpaper (cycle/next wallpaper/whitelist)))
+    (wallpaper/set wallpaper)
+    (message (string/format "Active wallpaper: %s" (f-filename wallpaper)))))
+
+(defun wallpaper/prev ()
+  "Cycles to the previous wallpaper."
+  (interactive)
+  (let ((wallpaper (cycle/prev wallpaper/whitelist)))
+    (wallpaper/set wallpaper)
+    (message (string/format "Active wallpaper: %s" (f-filename wallpaper)))))
+
+;; TODO: Define a macro that handles, next, prev, select, current for working
+;; with cycles, since this is a common pattern.
+
+(defun wallpaper/print-current ()
+  "Message the currently enabled wallpaper."
+  (interactive)
+  (message
+   (cycle/current wallpaper/whitelist)))
+
+(defun wallpaper/current ()
+  "Return the currently enabled wallpaper."
+  (cycle/current wallpaper/whitelist))
+
+(defun wallpaper/ivy-select ()
+  "Use `counsel' to select and set a wallpaper from the `wallpaper/whitelist'."
+  (interactive)
+  (wallpaper/whitelist-set
+   (ivy-read "Select wallpaper: " (cycle/to-list wallpaper/whitelist))))
+
+;; TODO: Create macro-based module system that will auto-namespace functions,
+;; constants, etc. with the filename like `wallpaper'.
+
+(when wallpaper/keybindings?
+  (general-define-key
+   :prefix "<SPC>"
+   :states '(normal)
+   "Fw" #'wallpaper/next
+   "Pw" #'wallpaper/prev))
+
+(provide 'wallpaper)
+;;; wallpaper.el ends here
diff --git a/emacs/.emacs.d/wpc/window-manager.el b/emacs/.emacs.d/wpc/window-manager.el
new file mode 100644
index 000000000000..cf7f1efeb799
--- /dev/null
+++ b/emacs/.emacs.d/wpc/window-manager.el
@@ -0,0 +1,647 @@
+;;; window-manager.el --- Functions augmenting my usage of EXWM. -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; I switched to EXWM from i3, and I haven't looked back.  One day I may write a
+;; poem declaring my love for Emacs and EXWM.  For now, I haven't the time.
+
+;; Wish list:
+;; - TODO: Support different startup commands and layouts depending on laptop or
+;;   desktop.
+;; - TODO: Support a Music named-workspace.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'alert)
+(require 'prelude)
+(require 'string)
+(require 'cycle)
+(require 'set)
+(require 'kbd)
+(require 'ivy-helpers)
+(require 'display)
+(require 'dotfiles)
+(require 'org-helpers)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Move this function to another module.
+(defun pkill (name)
+  "Call the pkill executable using NAME as its argument."
+  (interactive "sProcess name: ")
+  (call-process "pkill" nil nil nil name))
+
+;; TODO: Associate `window-purpose' window-layouts with each of these named
+;; workspaces.
+
+;; TODO: Associate KBDs for each of these named-layouts.
+
+;; TODO: Decide between window-manager, exwm, or some other namespace.
+
+;; TODO: Support (cycle/from-list '(current previous)) to toggle back and forth
+;; between most recent workspace.
+
+;; TODO: Support ad hoc cycle for loading a few workspaces that can be cycled
+;; between. (cycle/from-list '("Project" "Workspace"))
+
+;; TODO: Consider supporting a workspace for Racket, Clojure, Common Lisp,
+;; Haskell, Elixir, and a few other languages. These could behave very similarly
+;; to repl.it, which I've wanted to have locally for awhile now.
+
+;; TODO: Support MRU cache of workspaces for easily switching back-and-forth
+;; between workspaces.
+
+(cl-defstruct exwm/named-workspace
+  label
+  index
+  kbd)
+
+(defconst exwm/install-workspace-kbds? t
+  "When t, install the keybindings to switch between named-workspaces.")
+
+;; TODO: Consume `cache/touch' after changing workspaces.  Use this to enable
+;; cycling through workspaces.
+
+(defconst exwm/named-workspaces
+  (list (make-exwm/named-workspace
+         :label "Web surfing"
+         :index 0
+         :kbd "c")
+        (make-exwm/named-workspace
+         :label "Project"
+         :index 1
+         :kbd "p")
+        (make-exwm/named-workspace
+         :label "Dotfiles"
+         :index 2
+         :kbd "d")
+        (make-exwm/named-workspace
+         :label "Scratch"
+         :index 3
+         :kbd "s")
+        (make-exwm/named-workspace
+         :label "Terminal"
+         :index 4
+         :kbd "t")
+        (make-exwm/named-workspace
+         :label "Todos"
+         :index 5
+         :kbd "o")
+        (make-exwm/named-workspace
+         :label "Chatter"
+         :index 6
+         :kbd "h")
+        (make-exwm/named-workspace
+         :label "IRC"
+         :index 7
+         :kbd "i")
+        (make-exwm/named-workspace
+         :label "Work"
+         :index 8
+         :kbd "w"))
+  "List of `exwm/named-workspace' structs.")
+
+;; Assert that no two workspaces share KBDs.
+(prelude/assert (= (list/length exwm/named-workspaces)
+                   (->> exwm/named-workspaces
+                        (list/map #'exwm/named-workspace-kbd)
+                        set/from-list
+                        set/count)))
+
+(defun window-manager/alert (x)
+  "Message X with a structured format."
+  (alert (string/concat "[exwm] " x)))
+
+;; Use Emacs as my primary window manager.
+(use-package exwm
+  :config
+  (require 'exwm-config)
+
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  ;; Multiple Displays
+  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+  (require 'exwm-randr)
+  (exwm-randr-enable)
+  ;; TODO: Consider generating this plist.
+  ;; TODO: Replace integer index values with their named workspace equivalents.
+  (setq exwm-randr-workspace-monitor-plist
+        (list 0 display/4k-monitor
+              1 display/laptop-monitor))
+
+  (evil-set-initial-state 'exwm-mode 'emacs)
+  (ido-mode 1)
+  (exwm-config-ido)
+  (setq exwm-workspace-number
+        (list/length exwm/named-workspaces))
+  ;; EXWM supports "line-mode" and "char-mode".
+  ;;
+  ;; Note: It appears that calling `exwm-input-set-key' works if it's called
+  ;; during startup.  Once a session has started, it seems like this function is
+  ;; significantly less useful.  Is this a bug?
+  ;;
+  ;; Glossary:
+  ;; - char-mode: All keystrokes except `exwm' global ones are passed to the
+  ;;   application.
+  ;; - line-mode:
+  ;;
+  ;; `exwm-input-global-keys' = {line,char}-mode; can also call `exwm-input-set-key'
+  ;; `exwm-mode-map'          = line-mode
+  ;; `???'                    = char-mode. Is there a mode-map for this?
+  ;;
+  ;; TODO: What is `exwm-input-prefix-keys'?
+  ;; TODO: Once I get `exwm-input-global-keys' functions, drop support for
+  ;; `wpc/kbds'.
+  (let ((kbds `(
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+                ;; Window sizing
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+                (:key "C-M-=" :fn balance-windows)
+                ;; TODO: Make sure these don't interfere with LISP KBDs.
+                (:key "C-M-j" :fn shrink-window)
+                (:key "C-M-k" :fn enlarge-window)
+                (:key "C-M-h" :fn shrink-window-horizontally)
+                (:key "C-M-l" :fn enlarge-window-horizontally)
+
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+                ;; Window traversing
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+                (:key "M-h" :fn windmove-left)
+                (:key "M-j" :fn windmove-down)
+                (:key "M-k" :fn windmove-up)
+                (:key "M-l" :fn windmove-right)
+
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+                ;; Window splitting
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+                (:key "M-\\" :fn evil-window-vsplit)
+                (:key "M--"  :fn evil-window-split)
+
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+                ;; Window deletion
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+                (:key "M-q" :fn delete-window)
+
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+                ;; Miscellaneous
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+                (:key "M-:"               :fn eval-expression)
+                (:key "M-SPC"             :fn window-manager/apps)
+                (:key "M-x"               :fn counsel-M-x)
+                (:key "<M-tab>"           :fn exwm/next-workspace)
+                (:key "<M-S-iso-lefttab>" :fn exwm/prev-workspace)
+                (:key "<M-iso-lefttab>"   :fn exwm/prev-workspace)
+                ;; <M-escape> doesn't work in X11 windows.
+                (:key "<M-escape>"        :fn exwm/ivy-switch)
+                (:key "C-M-\\"            :fn ivy-pass)
+
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+                ;; REPLs
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+                (:key ,(kbd/raw 'x11 "r") :fn exwm/ivy-find-or-create-repl)
+
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+                ;; Workspaces
+                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+                ;; NOTE: Here I need to generate lowercase and uppercase
+                ;; variants of each because my Ergodox is sending capitalized
+                ;; variants of the keycodes to EXWM.
+                (:key ,(kbd/raw 'workspace "l") :fn window-manager/logout)
+                (:key ,(kbd/raw 'workspace "L") :fn window-manager/logout)
+                (:key ,(kbd/raw 'workspace "i") :fn exwm/toggle-mode)
+                (:key ,(kbd/raw 'workspace "I") :fn exwm/toggle-mode))))
+    (setq exwm-input-global-keys
+          (->> kbds
+               (-map (lambda (plist)
+                       `(,(kbd (plist-get plist :key)) . ,(plist-get plist :fn)))))))
+  (setq exwm-input-simulation-keys
+        ;; TODO: Consider supporting M-d and other readline style KBDs.
+        '(([?\C-b] . [left])
+          ([?\M-b] . [C-left])
+          ([?\C-f] . [right])
+          ([?\M-f] . [C-right])
+          ([?\C-p] . [up])
+          ([?\C-n] . [down])
+          ([?\C-a] . [home])
+          ([?\C-e] . [end])
+          ([?\C-d] . [delete])
+          ;; TODO: Assess whether or not this is a good idea.
+          ;; TODO: Ensure C-c copies.
+          ([?\C-c] . [C-c])))
+  (exwm-enable))
+
+;; TODO: Package workspace management in another module.
+
+;; Here is the code required to allow EXWM to cycle workspaces.
+(defconst exwm/workspaces
+  (->> exwm/named-workspaces
+       cycle/from-list)
+  "Cycle of the my EXWM workspaces.")
+
+(prelude/assert
+ (= exwm-workspace-number
+    (list/length exwm/named-workspaces)))
+
+(defun exwm/next-workspace ()
+  "Cycle forwards to the next workspace."
+  (interactive)
+  (exwm/change-workspace (cycle/next exwm/workspaces)))
+
+(defun exwm/prev-workspace ()
+  "Cycle backwards to the previous workspace."
+  (interactive)
+  (exwm/change-workspace (cycle/prev exwm/workspaces)))
+
+;; TODO: Create friendlier API for working with EXWM.
+
+;; Here is the code required to toggle EXWM's modes.
+(defun exwm/line-mode ()
+  "Switch exwm to line-mode."
+  (call-interactively #'exwm-input-grab-keyboard)
+  (window-manager/alert "Switched to line-mode"))
+
+(defun exwm/char-mode ()
+  "Switch exwm to char-mode."
+  (call-interactively #'exwm-input-release-keyboard)
+  (window-manager/alert "Switched to char-mode"))
+
+(defconst exwm/modes
+  (cycle/from-list (list #'exwm/char-mode
+                         #'exwm/line-mode))
+  "Functions to switch exwm modes.")
+
+(defun exwm/toggle-mode ()
+  "Switch between line- and char- mode."
+  (interactive)
+  (with-current-buffer (window-buffer)
+    (when (eq major-mode 'exwm-mode)
+      (funcall (cycle/next exwm/modes)))))
+
+;; Ensure exwm apps open in char-mode.
+(add-hook
+ 'exwm-manage-finish-hook
+ #'exwm/char-mode)
+
+;; Interface to the Linux password manager
+;; TODO: Consider writing a better client for this.
+(use-package ivy-pass)
+
+;; TODO: Prefer a more idiomatic Emacs way like `with-output-to-temp-buffer'.
+
+;; TODO: Create a mode similar to `help-mode' that also kills the buffer when
+;; "q" is pressed since this is sensitive information that we probably don't
+;; want persisting.
+
+;; TODO: Have this interactively show all of the listings in ~/.password-store
+;; in an ivy list.
+(defun password-store/show (key)
+  "Show the contents of KEY from the password-store in a buffer."
+  (interactive)
+  (let ((b (buffer/find-or-create (string/format "*password-store<%s>*" key))))
+    (with-current-buffer b
+      (insert (password-store-get key))
+      (help-mode))
+    (buffer/show b)))
+
+;; TODO: I'm having difficulties with the Nix-built terminator. The one at
+;; /usr/bin/terminator (i.e. built w/o Nix) works just fine. Using this,
+;; however, cheapens my Nix setup.
+(defconst exwm/preferred-terminal "terminator"
+  "My preferred terminal.")
+
+;; TODO: How do I handle this dependency?
+(defconst exwm/preferred-browser "google-chrome"
+  "My preferred web browser.")
+
+(defun exwm/browser-open (&optional url)
+  "Opens the URL in `exwm/preferred-browser'."
+  (exwm/open
+   (string/format "%s %s" exwm/preferred-browser url)
+   :buffer-name (string/format "*%s*<%s>" exwm/preferred-browser url)
+   :process-name url))
+
+;; TODO: Consider storing local state of all processes started with this command
+;; for some nice ways to cycle through existing terminals, etc.
+(defun exwm/terminal-open (cmd)
+  "Call CMD using `exwm/preferred-terminal'."
+  (exwm/open (string/format
+              "%s --command '%s'"
+              exwm/preferred-terminal
+              cmd)
+             :buffer-name (string/format "*%s*<%s>" exwm/preferred-terminal cmd)
+             :process-name cmd))
+
+;; TODO: Create a KBD that calls the `C-x b<Enter>' I call often.
+;; TODO: Consider auto-generating KBDs for spawning these using the first
+;; character in their name.  Also assert that none of the generated keybindings
+;; will clash with one another.
+(defconst exwm/repls
+  '(("python" . (lambda () (exwm/terminal-open "python3")))
+    ("zsh"    . (lambda () (exwm/terminal-open "zsh")))
+    ("fish"   . (lambda () (exwm/terminal-open "fish")))
+    ("nix"    . (lambda () (exwm/terminal-open "nix repl")))
+    ("racket" . racket-repl)
+    ;; NOTE: `ielm' as-is is a find-or-create operation.
+    ("elisp"  . ielm))
+  "Mapping of REPL labels to the commands needed to initialize those REPLs.")
+
+;; NOTE: Some of these commands split the window already.  Some of these
+;; commands find-or-create already.
+;;
+;; Find-or-create:
+;;        +---+---+
+;;        | Y | N |
+;;        +---+---+
+;; python |   | x |
+;; zsh    |   | x |
+;; racket | x |   |
+;; elisp  | x |   |
+;;        +---+---+
+;;
+;; Split:
+;;        +---+---+
+;;        | Y | N |
+;;        +---+---+
+;; python |   | x |
+;; zsh    |   | x |
+;; racket | x |   |
+;; elisp  |   | x |
+;;        +---+---+
+
+;; - Split:
+;;   - racket
+(defun exwm/ivy-find-or-create-repl ()
+  "Select a type of REPL using `ivy' and then find-or-create it."
+  (interactive)
+  (ivy-helpers/kv "REPLs: "
+                  exwm/repls
+                  (lambda (_ v)
+                    (funcall v))))
+
+;; KBDs to quickly open X11 applications.
+(general-define-key
+ ;; TODO: Eventually switch this to a find-or-create operation.  In general, I
+ ;; shouldn't need multiple instances of `python3` REPLs.
+ ;; TODO: Consider coupling these KBDs with the `exwm/ivy-find-or-create-repl'
+ ;; functionality defined above.
+ (kbd/raw 'x11 "n") (lambda ()
+                      (interactive)
+                      (exwm/terminal-open "nix repl"))
+ (kbd/raw 'x11 "p") (lambda ()
+                      (interactive)
+                      (exwm/terminal-open "python3"))
+ (kbd/raw 'x11 "t") (lambda ()
+                      (interactive)
+                      (exwm/open exwm/preferred-terminal))
+ (kbd/raw 'x11 "c") (lambda ()
+                      (interactive)
+                      (exwm/open exwm/preferred-browser)))
+
+;; TODO: Support searching all "launchable" applications like OSX's Spotlight.
+;; TODO: Model this as key-value pairs.
+(defconst window-manager/applications
+  (list "google-chrome --new-window --app=https://chat.google.com"
+        "google-chrome --new-window --app=https://calendar.google.com"
+        "google-chrome --new-window --app=https://gmail.com"
+        "telegram-desktop"
+        "google-chrome --new-window --app=https://teknql.slack.com"
+        "google-chrome --new-window --app=https://web.whatsapp.com"
+        "google-chrome --new-window --app=https://irccloud.com"
+        exwm/preferred-browser
+        exwm/preferred-terminal)
+  "Applications that I commonly use.
+These are the types of items that would usually appear in dmenu.")
+
+;; TODO: Consider replacing the `ivy-read' call with something like `hydra' that
+;; can provide a small mode for accepting user-input.
+;; TODO: Put this somewhere more diliberate.
+
+;; TODO: Configure the environment variables for xsecurelock so that the font is
+;; smaller, different, and the glinux wallpaper doesn't show.
+;; - XSECURELOCK_FONT="InputMono-Black 10"
+;; - XSECURE_SAVER=""
+;; - XSECURE_LOGO_IMAGE=""
+;; Maybe just create a ~/.xsecurelockrc
+;; TODO: Is there a shell-command API that accepts an alist and serializes it
+;; into variables to pass to the shell command?
+(defconst window-manager/xsecurelock
+  "/usr/share/goobuntu-desktop-files/xsecurelock.sh"
+  "Path to the proper xsecurelock executable.
+The other path to xsecurelock is /usr/bin/xsecurelock, which works fine, but it
+is not optimized for Goobuntu devices.  Goobuntu attempts to check a user's
+password using the network.  When there is no network connection available, the
+login attempts fail with an \"unknown error\", which isn't very helpful.  To
+avoid this, prefer the goobuntu wrapper around xsecurelock when on a goobuntu
+device.  This all relates to PAM (i.e. pluggable authentication modules).")
+
+(defun window-manager/logout ()
+  "Prompt the user for options for logging out, shutting down, etc.
+
+The following options are supported:
+- Lock
+- Logout
+- Suspend
+- Hibernate
+- Reboot
+- Shutdown
+
+Ivy is used to capture the user's input."
+  (interactive)
+  (let* ((name->cmd `(("Lock" . ,window-manager/xsecurelock)
+                      ("Logout" . "sudo systemctl stop lightdm")
+                      ("Suspend" . ,(string/concat
+                                     window-manager/xsecurelock
+                                     " && systemctl suspend"))
+                      ("Hibernate" . ,(string/concat
+                                       window-manager/xsecurelock
+                                       " && systemctl hibernate"))
+                      ("Reboot" . "systemctl reboot")
+                      ("Shutdown" . "systemctl poweroff"))))
+    (funcall
+     (lambda ()
+       (shell-command
+        (alist/get (ivy-read "System: " (alist/keys name->cmd))
+                   name->cmd))))))
+
+(cl-defun exwm/open (command &key
+                             (process-name command)
+                             (buffer-name command))
+  "Open COMMAND, which should be an X11 window."
+  (start-process-shell-command process-name buffer-name command))
+
+(cl-defun window-manager/execute-from-counsel (&key prompt list)
+  "Display a counsel menu of `LIST' with `PROMPT' and pipe the output through
+`start-process-shell-command'."
+  (let ((x (ivy-read prompt list)))
+    (exwm/open
+     x
+     :buffer-name (string/format "*exwm/open*<%s>" x)
+     :process-name x)))
+
+(defun window-manager/apps ()
+  "Open commonly used applications from counsel."
+  (interactive)
+  (window-manager/execute-from-counsel
+   :prompt "Application: "
+   :list window-manager/applications))
+
+(defun exwm/label->index (label workspaces)
+  "Return the index of the workspace in WORKSPACES named LABEL."
+  (let ((workspace (->> workspaces
+                        (list/find
+                         (lambda (x)
+                           (equal label
+                                  (exwm/named-workspace-label x)))))))
+    (if (prelude/set? workspace)
+        (exwm/named-workspace-index workspace)
+      (error (string/concat "No workspace found for label: " label)))))
+
+(defun exwm/register-kbd (workspace)
+  "Registers a keybinding for WORKSPACE struct.
+Currently using super- as the prefix for switching workspaces."
+  (let ((handler (lambda ()
+                   (interactive)
+                   (exwm/switch (exwm/named-workspace-label workspace))))
+        (key (exwm/named-workspace-kbd workspace)))
+    (exwm-input-set-key
+     (kbd/for 'workspace key)
+     handler)
+    ;; Note: We need to capitalize the KBD here because of the signals that my
+    ;; Ergodox is sending Emacs on my desktop.
+    (exwm-input-set-key
+     (kbd/for 'workspace (s-capitalize key))
+     handler)))
+
+(defun exwm/change-workspace (workspace)
+  "Switch EXWM workspaces to the WORKSPACE struct."
+  (exwm-workspace-switch (exwm/named-workspace-index workspace))
+  (window-manager/alert
+   (string/format "Switched to: %s" (exwm/named-workspace-label workspace))))
+
+(defun exwm/switch (label)
+  "Switch to a named workspaces using LABEL."
+  (cycle/focus (lambda (x)
+                 (equal label
+                        (exwm/named-workspace-label x)))
+               exwm/workspaces)
+  (exwm/change-workspace (cycle/current exwm/workspaces)))
+
+;; TODO: Assign an easy-to-remember keybinding to this.
+(exwm-input-set-key (kbd "C-S-f") #'exwm/toggle-previous)
+(defun exwm/toggle-previous ()
+  "Focus the previously active EXWM workspace."
+  (interactive)
+  (exwm/change-workspace (cycle/focus-previous! exwm/workspaces)))
+
+(defun exwm/ivy-switch ()
+  "Use ivy to switched between named workspaces."
+  (interactive)
+  (ivy-read
+   "Workspace: "
+   (->> exwm/named-workspaces
+        (list/map #'exwm/named-workspace-label))
+   :action #'exwm/switch))
+
+(when exwm/install-workspace-kbds?
+  (progn
+    (->> exwm/named-workspaces
+         (list/map #'exwm/register-kbd))
+    (window-manager/alert "Registered workspace KBDs!")))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Startup Applications in `exwm/named-workspaces'
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(add-hook
+ 'exwm-init-hook
+ (lambda ()
+   ;; TODO: Refactor this into a bigger solution where the named-workspaces are
+   ;; coupled to their startup commands.  Expedience wins this time.
+   (progn
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     ;; Chrome
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     (progn
+       (exwm/switch "Web surfing")
+       ;; make sure this blocks.
+       ;; TODO: Support shell-cmd.el that has `shell-cmd/{sync,async}'.
+       ;; (call-process-shell-command "google-chrome")
+       )
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     ;; Project
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     (progn
+       (exwm/switch "Project")
+       (find-file constants/current-project))
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     ;; Scratch
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     (progn
+       (exwm/switch "Scratch")
+       (switch-to-buffer "*scratch*"))
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     ;; Terminal
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     (progn
+       (exwm/switch "Terminal")
+       ;; TODO: Why does "gnome-terminal" work but not "terminator"?
+       ;; (call-process-shell-command "gnome-terminal")
+       )
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     ;; Todos
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     (progn
+       (exwm/switch "Todos")
+       (org-helpers/find-file "today-expected.org")
+       (wpc/evil-window-vsplit-right)
+       (org-helpers/find-file "today-actual.org"))
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     ;; Dotfiles
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     (progn
+       (exwm/switch "Dotfiles")
+       (dotfiles/find-emacs-file "init.el")
+       (wpc/evil-window-vsplit-right)
+       (dotfiles/find-emacs-file "wpc/window-manager.el"))
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     ;; Chatter
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     (progn
+       (exwm/switch "Chatter")
+       ;; TODO: Support the following chat applications:
+       ;; - Slack teknql
+       ;; - irccloud.net
+       ;; - web.whatsapp.com
+       ;; - Telegram
+       ;; NOTE: Perhaps all of these should be borderless.
+       ;; (call-process-shell-command "terminator")
+       )
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     ;; Work
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     (progn
+       (exwm/switch "Work")
+       ;; TODO: Support opening the following in chrome:
+       ;; - calendar
+       ;; - gmail
+       ;; - chat (in a horizontal split)
+       )
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     ;; Reset to default
+     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+     (exwm/switch "Dotfiles"))))
+
+(provide 'window-manager)
+;;; window-manager.el ends here
diff --git a/emacs/.emacs.d/wpc/window.el b/emacs/.emacs.d/wpc/window.el
new file mode 100644
index 000000000000..132156bc4465
--- /dev/null
+++ b/emacs/.emacs.d/wpc/window.el
@@ -0,0 +1,37 @@
+;;; window.el --- Working with Emacs windows -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Utilities to make CRUDing windows in Emacs easier.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'macros)
+(require 'maybe)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun window/find (name)
+  "Find a window by the NAME of the buffer it's hosting."
+  (let ((buffer (get-buffer name)))
+    (if (maybe/some? buffer)
+        (get-buffer-window buffer)
+      nil)))
+
+;; TODO: Find a way to incorporate these into function documentation.
+(macros/comment
+ (window/find "*scratch*"))
+
+(defun window/delete (window)
+  "Delete the WINDOW reference."
+  (delete-window window))
+
+(provide 'window)
+;;; window.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-clojure.el b/emacs/.emacs.d/wpc/wpc-clojure.el
new file mode 100644
index 000000000000..d9262cdda8eb
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-clojure.el
@@ -0,0 +1,85 @@
+;;; clojure.el --- My Clojure preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Hosting my Clojure tooling preferences
+
+;;; Code:
+
+;; Helper functions
+
+;; (defun wpc/buffer-name-for-clojure-mode (mode)
+;;   (let* ((project-name (projectile-project-name))
+;;          (cljs-name (concat "*cider-repl CLJS " project-name "*"))
+;;          (clj-name  (concat "*cider-repl " project-name "*")))
+;;     (cond ((eq mode 'clojurescript-mode) cljs-name)
+;;           ((eq mode 'clojure-mode) clj-name)
+;;           ((eq mode 'clojurec-mode) cljs-name))))
+
+;; (defun wpc/repl-function-for-clojure-mode (mode)
+;;   (let ((project-name (projectile-project-name))
+;;         (cljs-fn #'cider-jack-in-clojurescript)
+;;         (clj-fn  #'cider-jack-in))
+;;     (cond ((eq mode 'clojurescript-mode) cljs-fn)
+;;           ((eq mode 'clojure-mode) clj-fn)
+;;           ((eq mode 'clojurec-mode) cljs-fn))))
+
+;; (defun wpc/find-or-create-clojure-or-clojurescript-repl ()
+;;   (interactive)
+;;   (with-current-buffer (current-buffer)
+;;     (let ((buffer-name   (wpc/buffer-name-for-clojure-mode major-mode))
+;;           (repl-function (wpc/repl-function-for-clojure-mode major-mode)))
+;;       (if (get-buffer buffer-name)
+;;           (switch-to-buffer buffer-name)
+;;         (funcall repl-function)))))
+
+(use-package clojure-mode
+  :config
+  ;; from Ryan Schmukler:
+  (setq cljr-magic-require-namespaces
+        '(("io" . "clojure.java.io")
+          ("sh" . "clojure.java.shell")
+          ("jdbc" . "clojure.java.jdbc")
+          ("set" . "clojure.set")
+          ("time" . "java-time")
+          ("str" . "cuerdas.core")
+          ("path" . "pathetic.core")
+          ("walk" . "clojure.walk")
+          ("zip" . "clojure.zip")
+          ("async" . "clojure.core.async")
+          ("component" . "com.stuartsierra.component")
+          ("http" . "clj-http.client")
+          ("url" . "cemerick.url")
+          ("sql" . "honeysql.core")
+          ("csv" . "clojure.data.csv")
+          ("json" . "cheshire.core")
+          ("s" . "clojure.spec.alpha")
+          ("fs" . "me.raynes.fs")
+          ("ig" . "integrant.core")
+          ("cp" . "com.climate.claypoole")
+          ("re-frame" . "re-frame.core")
+          ("rf" . "re-frame.core")
+          ("re" . "reagent.core")
+          ("reagent" . "reagent.core")
+          ("u.core" . "utopia.core")
+          ("gen" . "clojure.spec.gen.alpha"))))
+
+(use-package cider
+  :config
+  (general-define-key
+    :keymaps 'cider-repl-mode-map
+    "C-l"    #'cider-repl-clear-buffer
+    "C-u"    #'kill-whole-line
+    "<up>"   #'cider-repl-previous-input
+    "<down>" #'cider-repl-next-input
+    ;; "C-c 'j" #'wpc/find-or-create-clojure-or-clojurescript-repl
+    )
+  ;; (setq cider-cljs-lein-repl
+  ;;       "(do (require 'figwheel-sidecar.repl-api)
+  ;;            (figwheel-sidecar.repl-api/start-figwheel!)
+  ;;            (figwheel-sidecar.repl-api/cljs-repl))"
+  ;;       cider-prompt-for-symbol nil)
+  )
+
+(provide 'wpc-clojure)
+;;; wpc-clojure.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-company.el b/emacs/.emacs.d/wpc/wpc-company.el
new file mode 100644
index 000000000000..1152f496c2b7
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-company.el
@@ -0,0 +1,28 @@
+;;; company.el --- Autocompletion package, company, preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Hosts my company mode preferences
+
+;;; Code:
+
+;; autocompletion client
+(use-package company
+  :config
+  (general-define-key
+    :keymaps 'company-active-map
+    "C-j" #'company-select-next
+    "C-n" #'company-select-next
+    "C-k" #'company-select-previous
+    "C-p" #'company-select-previous
+    "C-d" #'company-show-doc-buffer)
+  (setq company-tooltip-align-annotations t)
+  (setq company-idle-delay 0)
+  (setq company-show-numbers t)
+  (setq company-minimum-prefix-length 2)
+  (setq company-dabbrev-downcase nil
+        company-dabbrev-ignore-case t)
+  (global-company-mode))
+
+(provide 'wpc-company)
+;;; wpc-company.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-dired.el b/emacs/.emacs.d/wpc/wpc-dired.el
new file mode 100644
index 000000000000..bc3915914bf1
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-dired.el
@@ -0,0 +1,41 @@
+;;; dired.el --- My dired preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; File management in Emacs, if learned and configured properly, should be
+;; capable to reduce my dependency on the terminal.
+
+;;; Code:
+
+;; TODO: Ensure sorting in dired is by type.
+
+;; TODO: Rename wpc-dired.el to file-management.el
+
+(progn
+  (require 'dired)
+  (setq dired-recursive-copies 'always
+        dired-recursive-deletes 'top
+        dired-dwim-target t)
+  (general-define-key
+   :keymaps 'dired-mode-map
+   :states '(normal)
+   ;; Overriding some KBDs defined in the evil-collection module.
+   "o" #'dired-find-file-other-window
+   "<SPC>" nil ;; This unblocks some of my leader-prefixed KBDs.
+   "s" nil ;; This unblocks my window-splitting KBDs.
+   "c" #'find-file
+   "f" #'wpc/find-file
+   "-" (lambda () (interactive) (find-alternate-file "..")))
+  (general-add-hook 'dired-mode-hook
+                    (list (enable dired-hide-details-mode)
+                          #'auto-revert-mode)))
+
+(progn
+  (require 'locate)
+  (general-define-key
+   :keymaps 'locate-mode-map
+   :states 'normal
+   "o" #'dired-find-file-other-window))
+
+(provide 'wpc-dired)
+;;; wpc-dired.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-docker.el b/emacs/.emacs.d/wpc/wpc-docker.el
new file mode 100644
index 000000000000..270eaec6fe4c
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-docker.el
@@ -0,0 +1,16 @@
+;;; docker.el --- Docker preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; My Docker preferences and configuration
+
+;;; Code:
+
+(use-package docker
+  :config
+  (setenv "DOCKER_TLS_VERIFY" "1")
+  (setenv "DOCKER_HOST" "tcp://10.11.12.13:2376")
+  (setenv "DOCKER_MACHINE_NAME" "name"))
+
+(provide 'wpc-docker)
+;;; wpc-docker.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-elixir.el b/emacs/.emacs.d/wpc/wpc-elixir.el
new file mode 100644
index 000000000000..e64abe70fc36
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-elixir.el
@@ -0,0 +1,13 @@
+;;; wpc-elixir.el --- Elixir / Erland configuration -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; My preferences for working with Elixir / Erlang projects
+
+;;; Code:
+(use-package elixir-mode
+  :config
+  (add-hook-before-save 'elixir-mode-hook #'elixir-format))
+
+(provide 'wpc-elixir)
+;;; wpc-elixir.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-flycheck.el b/emacs/.emacs.d/wpc/wpc-flycheck.el
new file mode 100644
index 000000000000..d7bb834a6257
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-flycheck.el
@@ -0,0 +1,14 @@
+;;; flycheck.el --- My flycheck configuration -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Hosts my Flycheck preferences
+
+;;; Code:
+
+(use-package flycheck
+  :config
+  (global-flycheck-mode))
+
+(provide 'wpc-flycheck)
+;;; wpc-flycheck.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-haskell.el b/emacs/.emacs.d/wpc/wpc-haskell.el
new file mode 100644
index 000000000000..e8ab16e585b7
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-haskell.el
@@ -0,0 +1,56 @@
+;;; haskell.el --- My Haskell preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Hosts my Haskell development preferences
+
+;;; Code:
+
+;; Haskell support
+
+;; font-locking, glyph support, etc
+(use-package haskell-mode
+  :config
+  (let ((m-symbols
+         '(("`mappend`" . "⊕")
+           ("<>"        . "⊕"))))
+    (dolist (item m-symbols) (add-to-list 'haskell-font-lock-symbols-alist item)))
+  (setq haskell-font-lock-symbols t)
+  (add-hook-before-save 'haskell-mode #'haskell-align-imports))
+
+;; LSP support
+(use-package lsp-haskell
+  :after (haskell-mode)
+  :config
+  (setq lsp-haskell-process-path-hie "hie-wrapper")
+  (add-hook 'haskell-mode-hook #'lsp-haskell-enable)
+  (add-hook 'haskell-mode-hook #'flycheck-mode))
+
+;; Test toggling
+(defun haskell/module->test ()
+  "Jump from a module to a test."
+  (let ((filename (->> buffer-file-name
+                       (s-replace "/src/" "/test/")
+                       (s-replace ".hs" "Test.hs")
+                       find-file)))
+    (make-directory (f-dirname filename) t)
+    (find-file filename)))
+
+(defun haskell/test->module ()
+  "Jump from a test to a module."
+  (let ((filename (->> buffer-file-name
+                       (s-replace "/test/" "/src/")
+                       (s-replace "Test.hs" ".hs")
+                       )))
+    (make-directory (f-dirname filename) t)
+    (find-file filename)))
+
+(defun haskell/test<->module ()
+  "Toggle between test and module in Haskell."
+  (interactive)
+  (if (s-contains? "/src/" buffer-file-name)
+      (haskell/module->test)
+    (haskell/test->module)))
+
+(provide 'wpc-haskell)
+;;; wpc-haskell.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-java.el b/emacs/.emacs.d/wpc/wpc-java.el
new file mode 100644
index 000000000000..4f33ba962e5d
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-java.el
@@ -0,0 +1,42 @@
+;;; wpc-java.el --- Java configuration -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; When life gets you down, and you find yourself writing Java, remember: at
+;; least you're using Emacs.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'macros)
+
+(prelude/assert
+ (prelude/executable-exists? "google-java-format"))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Troubleshoot why this isn't running.
+(add-hook-before-save
+ 'java-mode-hook
+ (lambda ()
+   (call-interactively
+    #'google-java-format)))
+
+(add-hook 'java-mode-hook
+          (lambda ()
+            (setq c-basic-offset 2
+                  tab-width 2)))
+
+;; TODO: Figure out whether I should use this or google-emacs.
+;; (use-package lsp-java
+;;   :config
+;;   (add-hook 'java-mode-hook #'lsp))
+
+(provide 'wpc-java)
+;;; wpc-java.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-javascript.el b/emacs/.emacs.d/wpc/wpc-javascript.el
new file mode 100644
index 000000000000..3de9fff3aaa5
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-javascript.el
@@ -0,0 +1,83 @@
+;; wpc-javascript.el --- My Javascript preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; This module hosts my Javascript tooling preferences.  This also includes
+;; tooling for TypeScript and other frontend tooling.  Perhaps this module will
+;; change names to more accurately reflect that.
+;;
+;; Depends
+;; - yarn global add prettier
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Constants
+(defconst wpc/js-hooks
+  '(js-mode-hook web-mode-hook typescript-mode-hook js2-mode-hook rjsx-mode-hook)
+  "All of the commonly used hooks for Javascript buffers.")
+
+(defconst wpc/frontend-hooks
+  (-insert-at 0 'css-mode-hook wpc/js-hooks)
+  "All of the commonly user hooks for frontend development.")
+
+
+;; frontend indentation settings
+(setq typescript-indent-level 2
+      js-indent-level 2
+      css-indent-offset 2)
+
+;; Flow for Javascript
+(use-package add-node-modules-path
+  :config
+  (general-add-hook wpc/js-hooks #'add-node-modules-path))
+
+(use-package web-mode
+  :mode "\\.html\\'"
+  :config
+  (setq web-mode-css-indent-offset 2)
+  (setq web-mode-code-indent-offset 2)
+  (setq web-mode-markup-indent-offset 2))
+
+;; JSX highlighting
+(use-package rjsx-mode
+  :mode "\\.js\\'"
+  :config
+  (general-unbind rjsx-mode-map "<" ">" "C-d")
+  (general-nmap
+    :keymaps 'rjsx-mode-map
+    "K" #'flow-minor-type-at-pos)
+  (setq js2-mode-show-parse-errors nil
+        js2-mode-show-strict-warnings nil))
+
+(progn
+  (defun tide/setup ()
+    (interactive)
+    (tide-setup)
+    (flycheck-mode 1)
+    (setq flycheck-check-syntax-automatically '(save mode-enabled))
+    (eldoc-mode 1)
+    (tide-hl-identifier-mode 1)
+    (company-mode 1))
+  (use-package tide
+    :config
+    (add-hook 'typescript-mode-hook #'tide/setup))
+  (require 'web-mode)
+  (add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode))
+  (add-hook 'web-mode-hook
+            (lambda ()
+              (when (string-equal "tsx" (f-ext buffer-file-name))
+                (tide/setup))))
+  (flycheck-add-mode 'typescript-tslint 'web-mode))
+
+;; JS autoformatting
+(use-package prettier-js
+  :after (rjsx-mode)
+  :config
+  (general-add-hook wpc/frontend-hooks #'prettier-js-mode))
+
+(provide 'wpc-javascript)
+;;; wpc-javascript.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-keybindings.el b/emacs/.emacs.d/wpc/wpc-keybindings.el
new file mode 100644
index 000000000000..2ff4fe375829
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-keybindings.el
@@ -0,0 +1,229 @@
+;;; keybindings.el --- My Evil preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; This module hosts my Evil preferences
+;;
+;; Wish List:
+;; - restore support for concise (n <kbd> <function>) instead of `general-mmap'
+;; - restore support for `general-unbind'
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'general)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Packages
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; This may be contraversial, but I never use the prefix key, and I'd prefer to
+;; have to bound to the readline function that deletes the entire line.
+(general-unbind "C-u")
+
+(use-package evil
+  :init
+  ;; Should remove the warning messages on init.
+  (setq evil-want-integration t)
+  ;; TODO: Troubleshoot why this binding causes the following warning:
+  ;; "Warning (evil-collection): `evil-want-keybinding' was set to nil but not
+  ;; before loading evil."
+  (setq evil-want-keybinding nil)
+  (general-evil-setup)
+  :config
+  ;; Ensure that evil's command mode behaves with readline bindings.
+  (general-define-key
+   :keymaps 'evil-ex-completion-map
+   "C-a" #'move-beginning-of-line
+   "C-e" #'move-end-of-line
+   "C-k" #'kill-line
+   "C-u" #'evil-delete-whole-line
+   "C-v" #'evil-paste-after
+   "C-d" #'delete-char
+   "C-f" #'forward-char
+   "M-b" #'backward-word
+   "M-f" #'forward-word
+   "M-d" #'kill-word
+   "M-DEL" #'backward-kill-word
+   "C-b" #'backward-char)
+  ;; TODO: Ensure all of my custom keybindings end up in a single map that is
+  ;; easy to enable or disable.
+  (general-mmap
+    :keymaps 'override
+    "RET" #'evil-goto-line
+    "H"   #'evil-first-non-blank
+    "L"   #'evil-end-of-line
+    "_"   #'ranger
+    "-"   #'dired-jump
+    "sl"  #'wpc/evil-window-vsplit-right
+    "sh"  #'evil-window-vsplit
+    "sk"  #'evil-window-split
+    "sj"  #'wpc/evil-window-split-down)
+  (general-nmap
+    :keymaps 'override
+    "gd" #'xref-find-definitions
+    ;; Wrapping `xref-find-references' in the `let' binding to prevent xref from
+    ;; prompting.  There are other ways to handle this variable, such as setting
+    ;; it globally with `setq' or buffer-locally with `setq-local'.  For now, I
+    ;; prefer setting it with `let', which should bind it in the dynamic scope
+    ;; for the duration of the `xref-find-references' function call.
+    "gx" (lambda ()
+           (interactive)
+           (let ((xref-prompt-for-identifier nil))
+             (call-interactively #'xref-find-references))))
+  (general-unbind 'motion "M-." "C-p")
+  (general-unbind 'normal "s"   "M-." "C-p" "C-n")
+  (general-unbind 'insert "C-v" "C-d" "C-a" "C-e" "C-n" "C-p" "C-k")
+  (setq evil-symbol-word-search t)
+  (evil-mode 1))
+
+;; TODO: Write `evil-collection' KBDs for `refine'.
+;; evil keybindings
+(use-package evil-collection
+  :after (evil)
+  :config
+  (evil-collection-init))
+
+;; `evil-collection' does not support `magit', and the preferred way to get evil
+;; kbds for magit is with `evil-magit'.
+(use-package evil-magit)
+
+;; TODO: Consider moving this to another module.
+(general-define-key
+ :prefix "<SPC>"
+ :states '(normal)
+ "i" #'counsel-semantic-or-imenu
+ "I" #'ibuffer
+ "hk" #'helpful-callable
+ "hf" #'helpful-function
+ "hm" #'helpful-macro
+ "hc" #'helpful-command
+ "hk" #'helpful-key
+ "hv" #'helpful-variable
+ "hp" #'helpful-at-point
+ "s" #'flyspell-mode
+ "S" #'sort-lines
+ "a" #'wpc-terminal/toggle
+ "=" #'align
+ "p" #'flycheck-previous-error
+ "f" #'wpc/find-file
+ "n" #'flycheck-next-error
+ "N" #'smerge-next
+ "W" #'balance-windows
+ "gs" #'magit-status
+ "E" #'refine
+ "es" #'wpc/create-snippet
+ ;; TODO: Replace with `macros/ilambda' when that is working again.
+ "ev" (lambda () (interactive) (wpc/find-file-split "~/.config/nvim/init.vim"))
+ "ee" (lambda () (interactive) (wpc/find-file-split "~/.emacs.d/init.el"))
+ "ez" (lambda () (interactive) (wpc/find-file-split "~/.zshrc"))
+ "ea" (lambda () (interactive) (wpc/find-file-split "~/aliases.zsh"))
+ "ef" (lambda () (interactive) (wpc/find-file-split "~/functions.zsh"))
+ "el" (lambda () (interactive) (wpc/find-file-split "~/variables.zsh"))
+ "ex" (lambda () (interactive) (wpc/find-file-split "~/.Xresources"))
+ "em" (lambda () (interactive) (wpc/find-file-split "~/.tmux.conf"))
+ "l" #'locate
+ "L" #'list-packages
+ "B" #'magit-blame
+ "w" #'save-buffer
+ "r" #'wpc/evil-replace-under-point
+ "R" #'deadgrep)
+
+;; create comments easily
+(use-package evil-commentary
+  :after (evil)
+  :config
+  (evil-commentary-mode))
+
+;; evil surround
+(use-package evil-surround
+  :after (evil)
+  :config
+  (global-evil-surround-mode 1))
+
+;; I expect in insert mode:
+;; C-a: beginning-of-line
+;; C-e: end-of-line
+;; C-b: backwards-char
+;; C-f: forwards-char
+
+;; TODO: Move these KBD constants to kbd.el.
+
+(defconst wpc/up-kbds
+  '("C-p" "C-k" "<backtab>" "<up>")
+  "The keybindings that I expect to work for moving upwards in lists.")
+
+(defconst wpc/down-kbds
+  '("C-n" "C-j" "<tab>" "<down>")
+  "The keybindings that I expect to work for moving downwards in lists.")
+
+(defconst wpc/left-kbds
+  '("C-b" "<left>")
+  "The keybindings that I expect to move leftwards in insert-like modes.")
+
+(defconst wpc/right-kbds
+  '("C-f" "<right>")
+  "The keybindings that I expect to move rightwards in insert-like modes.")
+
+(defun wpc/ensure-kbds (_ignore)
+  "Try to ensure that my keybindings retain priority over other minor modes."
+  (unless (eq (caar minor-mode-map-alist) 'wpc/kbds-minor-mode)
+    (let ((mykbds (assq 'wpc/kbds-minor-mode minor-mode-map-alist)))
+      (assq-delete-all 'wpc/kbds-minor-mode minor-mode-map-alist)
+      (add-to-list 'minor-mode-map-alist mykbds))))
+
+;; Custom minor mode that ensures that my kbds are available no matter which
+;; major or minor modes are active.
+(add-hook 'after-load-functions #'wpc/ensure-kbds)
+
+;; TODO: Prefer using general and 'override maps to implement this.
+(defvar wpc/kbds
+  (let ((map (make-sparse-keymap)))
+    (bind-keys :map map
+               ("M-q"            . delete-window)
+               ("<s-return>"     . toggle-frame-fullscreen)
+               ("M-h"            . windmove-left)
+               ("M-l"            . windmove-right)
+               ("M-k"            . windmove-up)
+               ("M-j"            . windmove-down)
+               ("M-q"            . delete-window))
+    map)
+  "William Carroll's keybindings that should have the highest precedence.")
+
+;; Support pasting in M-:.
+(general-define-key
+ :keymaps 'read-expression-map
+ "C-v"   #'clipboard-yank
+ "C-S-v" #'clipboard-yank)
+
+(define-minor-mode wpc/kbds-minor-mode
+  "A minor mode so that my key settings override annoying major modes."
+  :init-value t
+  :lighter " wpc/kbds"
+  :keymap wpc/kbds)
+
+;; allow jk to escape
+(use-package key-chord
+  :after (evil)
+  :config
+  (key-chord-mode 1)
+  (key-chord-define evil-insert-state-map "jk" 'evil-normal-state))
+
+;; Ensure the Evil search results get centered vertically.
+;; TODO: Consider packaging this up for others.
+(progn
+  (defadvice isearch-update
+      (before advice-for-isearch-update activate)
+    (evil-scroll-line-to-center (line-number-at-pos)))
+  (defadvice evil-search-next
+      (after advice-for-evil-search-next activate)
+    (evil-scroll-line-to-center (line-number-at-pos)))
+  (defadvice evil-search-previous
+      (after advice-for-evil-search-previous activate)
+    (evil-scroll-line-to-center (line-number-at-pos))))
+
+(provide 'wpc-keybindings)
+;;; wpc-keybindings.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-lisp.el b/emacs/.emacs.d/wpc/wpc-lisp.el
new file mode 100644
index 000000000000..1eeb8550a205
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-lisp.el
@@ -0,0 +1,111 @@
+;;; lisp.el --- Generic LISP preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;; parent (up)
+;; child (down)
+;; prev-sibling (left)
+;; next-sibling (right)
+
+;;; Code:
+
+;; TODO: Consider having a separate module for each LISP dialect.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'general)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst wpc/lisp-mode-hooks
+  '(lisp-mode-hook
+    emacs-lisp-mode-hook
+    clojure-mode-hook
+    clojurescript-mode-hook
+    racket-mode-hook)
+  "List of LISP modes.")
+
+(use-package sly
+  :config
+  (setq inferior-lisp-program "sbcl")
+  (general-define-key
+   :keymaps 'sly-mode-map
+   :states '(normal)
+   :prefix "<SPC>"
+   "x" #'sly-eval-defun
+   "X" #'sly-eval-buffer
+   "d" #'sly-describe-symbol))
+
+(use-package rainbow-delimiters
+  :config
+  (general-add-hook wpc/lisp-mode-hooks #'rainbow-delimiters-mode))
+
+(use-package racket-mode
+  :config
+  (general-define-key
+   :keymaps 'racket-mode-map
+   :states 'normal
+   :prefix "<SPC>"
+   "x" #'racket-send-definition
+   "X" #'racket-run
+   "d" #'racket-describe)
+  (setq racket-program "~/.nix-profile/bin/racket"))
+
+(use-package lispyville
+  :init
+  (defconst lispyville-key-themes
+    '(c-w
+      operators
+      text-objects
+      prettify
+      commentary
+      slurp/barf-cp
+      wrap
+      additional
+      additional-insert
+      additional-wrap
+      escape)
+    "All available key-themes in Lispyville.")
+  :config
+  (general-add-hook wpc/lisp-mode-hooks #'lispyville-mode)
+  (lispyville-set-key-theme lispyville-key-themes)
+  (progn
+    (general-define-key
+     :keymaps 'lispyville-mode-map
+     :states 'motion
+     ;; first unbind
+     "M-h" nil
+     "M-l" nil)
+    (general-define-key
+     :keymaps 'lispyville-mode-map
+     :states 'normal
+     ;; first unbind
+     "M-j" nil
+     "M-k" nil
+     ;; second rebind
+     "C-s-h" #'lispyville-drag-backward
+     "C-s-l" #'lispyville-drag-forward
+     "C-s-e" #'lispyville-end-of-defun
+     "C-s-a" #'lispyville-beginning-of-defun)))
+
+;; Elisp
+(use-package elisp-slime-nav
+  :config
+  (general-add-hook 'emacs-lisp-mode #'ielm-mode))
+
+(general-define-key
+ :keymaps 'emacs-lisp-mode-map
+ :prefix "<SPC>"
+ :states 'normal
+ "x" #'eval-defun
+ "X" #'eval-buffer
+ "d" (lambda ()
+       (interactive)
+       (with-current-buffer (current-buffer)
+         (helpful-function (symbol-at-point)))))
+
+(provide 'wpc-lisp)
+;;; wpc-lisp.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-misc.el b/emacs/.emacs.d/wpc/wpc-misc.el
new file mode 100644
index 000000000000..167c4b88ab9c
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-misc.el
@@ -0,0 +1,248 @@
+;;; misc.el --- Hosting miscellaneous configuration -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; This is the home of any configuration that couldn't find a better home.
+
+;;; Code:
+
+;; Display time in the modeline
+;; TODO: Save preferred date format strings and cycle through them since I waver
+;; about which is my favorite.
+(setq display-time-format "%R %a %d %b [%U of 52 weeks]")
+(display-time-mode 1)
+
+;; disable custom variable entries from being written to ~/.emacs.d/init.el
+(setq custom-file "~/.emacs.d/custom.el")
+(load custom-file 'noerror)
+
+;; integrate Emacs with X11 clipboard
+(setq select-enable-primary t)
+(setq select-enable-clipboard t)
+(general-def 'insert
+  "s-v" #'clipboard-yank
+  "C-S-v" #'clipboard-yank)
+
+;; transparently edit compressed files
+(auto-compression-mode t)
+
+;; autowrap when over the fill-column
+(setq-default auto-fill-function #'do-auto-fill)
+
+;; link to Emacs source code
+;; TODO: Update this link.
+(setq find-function-C-source-directory
+      "~/Dropbox/programming/emacs/src")
+
+;; change emacs prompts from "yes or no" -> "y or n"
+(fset 'yes-or-no-p 'y-or-n-p)
+
+;; open photos in Emacs
+(auto-image-file-mode 1)
+
+;; disable line-wrapping
+(setq-default truncate-lines 1)
+
+;; shell file indentation
+(setq sh-basic-offset 2)
+(setq sh-indentation 2)
+
+;; Emacs library that interfaces with my Linux password manager.
+(use-package password-store)
+
+;; Use en Emacs buffer as a REST client.
+;; For more information: http://emacsrocks.com/e15.html
+(use-package restclient)
+
+;; Run `package-lint' before publishing to MELPA.
+(use-package package-lint)
+
+;; Parser combinators in Elisp.
+(use-package parsec)
+
+;; disable company mode when editing markdown
+;; TODO: move this out of wpc-misc.el and into a later file to call
+;; `(disable company-mode)'
+(use-package markdown-mode
+  :config
+  ;; TODO: Add assertion that pandoc is installed and it is accessible from
+  ;; Emacs.
+  (setq markdown-command "pandoc")
+  (setq markdown-split-window-direction 'right)
+  ;; (add-hook 'markdown-mode-hook #'markdown-live-preview-mode)
+  )
+
+(use-package alert)
+
+(use-package refine)
+
+;; Required by some google-emacs package commands.
+(use-package deferred)
+
+;; git integration
+(use-package magit
+  :config
+  (setq magit-display-buffer-function
+        #'magit-display-buffer-fullframe-status-v1))
+
+(use-package magit-popup)
+
+;; http
+(use-package request)
+
+;; perl-compatible regular expressions
+(use-package pcre2el)
+
+;; alternative to help
+(use-package helpful)
+
+;; Emacs integration with direnv
+(use-package direnv
+  :config
+  (direnv-mode))
+
+;; Superior Elisp library for working with dates and times.
+;; TODO: Put this where my other installations for dash.el, s.el, a.el, and
+;; other utility Elisp libraries are located.
+(use-package ts)
+
+;; persist history etc b/w Emacs sessions
+(setq desktop-save 'if-exists)
+(desktop-save-mode 1)
+(setq desktop-globals-to-save
+      (append '((extended-command-history . 30)
+                (file-name-history        . 100)
+                (grep-history             . 30)
+                (compile-history          . 30)
+                (minibuffer-history       . 50)
+                (query-replace-history    . 60)
+                (read-expression-history  . 60)
+                (regexp-history           . 60)
+                (regexp-search-ring       . 20)
+                (search-ring              . 20)
+                (shell-command-history    . 50)
+                tags-file-name
+                register-alist)))
+
+;; config Emacs to use $PATH values
+(use-package exec-path-from-shell
+  :if (memq window-system '(mac ns))
+  :config
+  (exec-path-from-shell-initialize))
+
+;; Emacs autosave, backup, interlocking files
+(setq auto-save-default nil
+      make-backup-files nil
+      create-lockfiles nil)
+
+;; ensure code wraps at 80 characters by default
+(setq-default fill-column constants/fill-column)
+
+(put 'narrow-to-region 'disabled nil)
+
+;; trim whitespace on save
+(add-hook 'before-save-hook #'delete-trailing-whitespace)
+
+;; use tabs instead of spaces
+(setq-default indent-tabs-mode nil)
+
+;; automatically follow symlinks
+(setq vc-follow-symlinks t)
+
+;; fullscreen settings
+(defvar ns-use-native-fullscreen nil)
+
+;; auto-close parens, brackets, quotes
+(electric-pair-mode 1)
+
+(use-package yasnippet
+  :config
+  (setq yas-snippet-dirs '("~/.emacs.d/snippets/"))
+  (yas-global-mode 1))
+
+(use-package projectile
+  :config
+  (projectile-mode t))
+
+(use-package deadgrep
+  :config
+  (general-define-key
+   :keymaps 'deadgrep-mode-map
+   :states 'normal
+   "o" #'deadgrep-visit-result-other-window)
+  (setq-default deadgrep--context '(0 . 3))
+  (defun deadgrep/region ()
+    "Run a ripgrep search on the active region."
+    (interactive)
+    (deadgrep (region/to-string)))
+  (defun deadgrep/dwim ()
+    "If a region is active, use that as the search, otherwise don't."
+    (interactive)
+    (with-current-buffer (current-buffer)
+      (if (region-active-p)
+          (setq deadgrep--additional-flags '("--multiline"))
+          (deadgrep/region)
+        (call-interactively #'deadgrep))))
+  (advice-add
+   'deadgrep--format-command
+   :filter-return
+   (lambda (cmd)
+     (replace-regexp-in-string
+      "^rg " "rg --hidden " cmd))))
+
+;; TODO: Do I need this when I have swiper?
+(use-package counsel)
+
+(use-package counsel-projectile)
+
+;; search Google, Stackoverflow from within Emacs
+(use-package engine-mode
+  :config
+  (defengine google
+    "http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s"
+    :keybinding "g")
+  (defengine stack-overflow
+    "https://stackoverflow.com/search?q=%s"
+    :keybinding "s"))
+
+;; EGlot (another LSP client)
+(use-package eglot)
+
+;; Microsoft's Debug Adapter Protocol (DAP)
+(use-package dap-mode
+  :after lsp-mode
+  :config
+  (dap-mode 1)
+  (dap-ui-mode 1))
+
+;; Microsoft's Language Server Protocol (LSP)
+(use-package lsp-ui
+  :config
+  (add-hook 'lsp-mode-hook #'lsp-ui-mode))
+
+(use-package company-lsp
+  :config
+  (push 'company-lsp company-backends))
+
+;; Wilfred/suggest.el - Tool for discovering functions basesd on declaring your
+;; desired inputs and outputs.
+(use-package suggest)
+
+;; Malabarba/paradox - Enhances the `list-packages' view.
+(use-package paradox
+  :config
+  (paradox-enable))
+
+;; TODO: Consider supporting a wpc-elisp.el package for Elisp tooling.
+;; The following functions are quite useful for Elisp development:
+;; - `emr-el-find-unused-definitions'
+(use-package emr
+  :config
+  (define-key prog-mode-map (kbd "M-RET") #'emr-show-refactor-menu))
+
+(defun wpc/frame-name ()
+  "Return the name of the current frame."
+  (frame-parameter nil 'name))
+
+(provide 'wpc-misc)
+;;; wpc-misc.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-nix.el b/emacs/.emacs.d/wpc/wpc-nix.el
new file mode 100644
index 000000000000..68d542e01176
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-nix.el
@@ -0,0 +1,56 @@
+;;; wpc-nix.el --- Nix support -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Configuration to support working with Nix.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(prelude/assert (f-exists? "~/universe"))
+(prelude/assert (f-exists? "~/depot"))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; Code:
+(use-package nix-mode
+  :mode "\\.nix\\'")
+
+(defun nix/sly-from-universe (attribute)
+  "Start a Sly REPL configured with a Lisp matching a derivation
+  from my monorepo.
+
+This function was taken from @tazjin's depot and adapted for my monorepo.
+
+  The derivation invokes nix.buildLisp.sbclWith and is built
+  asynchronously. The build output is included in the error
+  thrown on build failures."
+  (interactive "sAttribute: ")
+  (lexical-let* ((outbuf (get-buffer-create (format "*universe-out/%s*" attribute)))
+         (errbuf (get-buffer-create (format "*universe-errors/%s*" attribute)))
+         (expression (format "let depot = import <depot> {}; universe = import <universe> {}; in depot.nix.buildLisp.sbclWith [ universe.%s ]" attribute))
+         (command (list "nix-build" "-E" expression)))
+    (message "Acquiring Lisp for <depot>.%s" attribute)
+    (make-process :name (format "depot-nix-build/%s" attribute)
+                  :buffer outbuf
+                  :stderr errbuf
+                  :command command
+                  :sentinel
+                  (lambda (process event)
+                    (unwind-protect
+                        (pcase event
+                          ("finished\n"
+                           (let* ((outpath (s-trim (with-current-buffer outbuf (buffer-string))))
+                                  (lisp-path (s-concat outpath "/bin/sbcl")))
+                             (message "Acquired Lisp for <depot>.%s at %s" attribute lisp-path)
+                             (sly lisp-path)))
+                          (_ (with-current-buffer errbuf
+                               (error "Failed to build '%s':\n%s" attribute (buffer-string)))))
+                      (kill-buffer outbuf)
+                      (kill-buffer errbuf))))))
+
+(provide 'wpc-nix)
+;;; wpc-nix.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-ocaml.el b/emacs/.emacs.d/wpc/wpc-ocaml.el
new file mode 100644
index 000000000000..26add2d6f957
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-ocaml.el
@@ -0,0 +1,43 @@
+;;; wpc-ocaml.el --- My OCaml preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Tooling support for OCaml development.
+;;
+;; Dependencies:
+;; - `opam install tuareg`
+;; - `opam install merlin`
+;; - `opam install user-setup && opam user-setup install`
+;; - `opam install ocamlformat`
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'f)
+
+(prelude/assert
+ (prelude/executable-exists? "opam"))
+
+(defvar opam-user-setup "~/.emacs.d/opam-user-setup.el"
+  "File for the OPAM Emacs integration.")
+
+(prelude/assert (f-file? opam-user-setup))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(use-package tuareg
+  :config
+  (add-hook-before-save 'tuareg-mode-hook #'ocamlformat-before-save))
+
+;; ocamlformat
+(require 'opam-user-setup "~/.emacs.d/opam-user-setup.el")
+(require 'ocamlformat)
+
+(provide 'wpc-ocaml)
+;;; wpc-ocaml.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-org.el b/emacs/.emacs.d/wpc/wpc-org.el
new file mode 100644
index 000000000000..3263fb50380c
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-org.el
@@ -0,0 +1,70 @@
+;;; org.el --- My org preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Hosts my org mode preferences
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'f)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(setq org-directory "~/Dropbox/org")
+
+;; TODO: figure out how to nest this in (use-package org ...)
+(setq org-capture-templates
+      `(("w" "work" entry (file+headline
+                           ,(f-join org-directory "work.org")
+                           "Tasks")
+         "* TODO %?")
+        ("p" "personal" entry (file+headline
+                               ,(f-join org-directory "personal.org")
+                               "Tasks")
+         "* TODO %? ")
+        ("i" "ideas" entry (file+headline
+                            ,(f-join org-directory "ideas.org")
+                            "Tasks")
+         "* %? ")
+        ("s" "shopping list" entry (file+headline
+                            ,(f-join org-directory "shopping.org")
+                            "Items")
+         "* TODO %? ")))
+
+(evil-set-initial-state 'org-mode 'normal)
+
+(use-package org
+  :config
+  (general-add-hook 'org-mode-hook
+                    ;; TODO: consider supporting `(disable (list linum-mode company-mode))'
+                    (list (disable linum-mode)
+                          (disable company-mode)))
+  (general-define-key :prefix "C-c"
+           "l" #'org-store-link
+           "a" #'org-agenda
+           "c" #'org-capture)
+  (setq org-startup-folded nil)
+  (setq org-todo-keywords
+        '((sequence "TODO" "BLOCKED" "DONE")))
+  (setq org-default-notes-file (f-join org-directory "notes.org"))
+  (setq org-agenda-files (list (f-join org-directory "work.org")
+                               (f-join org-directory "personal.org")))
+  ;; TODO: troubleshoot why `wpc/kbds-minor-mode', `wpc/ensure-kbds' aren't
+  ;; enough to override the following KBDs. See this discussion for more context
+  ;; on where the idea came from:
+  ;; https://stackoverflow.com/questions/683425/globally-override-key-binding-in-emacs
+  (general-unbind 'normal org-mode-map "M-h" "M-j" "M-k" "M-l"))
+
+(use-package org-bullets
+  :after (org)
+  :config
+  (general-add-hook 'org-mode-hook (enable org-bullets-mode)))
+
+(provide 'wpc-org)
+;;; wpc-org.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-package.el b/emacs/.emacs.d/wpc/wpc-package.el
new file mode 100644
index 000000000000..5fd7a89982fb
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-package.el
@@ -0,0 +1,27 @@
+;;; package.el --- My package configuration -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; This module hosts all of the settings required to work with ELPA,
+;; MELPA, QUELPA, and co.
+
+;;; Code:
+
+(require 'package)
+
+;; Even though we're packaging our Emacs with Nix, having MELPA registered is
+;; helpful to ad-hoc test out packages before declaratively adding them to
+;; emacs/default.nix.
+(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
+(package-initialize)
+
+(unless (package-installed-p 'use-package)
+  ;; TODO: Consider removing this to improve initialization speed.
+  (package-refresh-contents)
+  (package-install 'use-package))
+(eval-when-compile
+  (require 'use-package))
+(use-package general)
+
+(provide 'wpc-package)
+;;; wpc-package.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-prolog.el b/emacs/.emacs.d/wpc/wpc-prolog.el
new file mode 100644
index 000000000000..94e705b1b114
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-prolog.el
@@ -0,0 +1,16 @@
+;;; wpc-prolog.el --- For Prologging things -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Code configuring my Prolog work.
+
+;;; Code:
+
+(require 'macros)
+
+;; TODO: Notice that the .pl extension conflicts with Perl files. This may
+;; become a problem should I start working with Perl.
+(macros/support-file-extension "pl" prolog-mode)
+
+(provide 'wpc-prolog)
+;;; wpc-prolog.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-python.el b/emacs/.emacs.d/wpc/wpc-python.el
new file mode 100644
index 000000000000..25f1a4816a67
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-python.el
@@ -0,0 +1,21 @@
+;;; wpc-python.el --- Python configuration -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; My Python configuration settings
+;;
+;; Depends
+;; - `apti yapf`
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(use-package py-yapf
+  :config
+  (add-hook 'python-mode-hook #'py-yapf-enable-on-save))
+
+(provide 'wpc-python)
+;;; wpc-python.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-reasonml.el b/emacs/.emacs.d/wpc/wpc-reasonml.el
new file mode 100644
index 000000000000..909c33d121f7
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-reasonml.el
@@ -0,0 +1,29 @@
+;;; wpc-reasonml.el --- My ReasonML preferences -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Tooling support for ReasonML development.
+;;
+;; Dependencies:
+;; - `opam install tuareg`
+;; - `opam install merlin`
+;; - `opam install user-setup`
+;; - `opam install ocamlformat`
+
+;;; Code:
+
+;; ReasonML configuration
+(use-package reason-mode
+  :config
+  (add-hook-before-save 'reason-mode-hook #'refmt-before-save))
+
+;; ReasonML LSP configuration
+(lsp-register-client
+ (make-lsp-client :new-connection (lsp-stdio-connection (f-full "~/programming/dependencies/reason-language-server"))
+                  :major-modes '(reason-mode)
+                  :notification-handlers (ht ("client/registerCapability" 'ignore))
+                  :priority 1
+                  :server-id 'reason-ls))
+
+(provide 'wpc-reasonml)
+;;; wpc-reasonml.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-rust.el b/emacs/.emacs.d/wpc/wpc-rust.el
new file mode 100644
index 000000000000..fafa27d18c77
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-rust.el
@@ -0,0 +1,34 @@
+;;; wpc-rust.el --- Support Rust language -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Supports my Rust work.
+;;
+;; Dependencies:
+;; - `rustup`
+;; - `rustup component add rust-src`
+;; - `rustup toolchain add nightly && cargo +nightly install racer`
+
+
+;;; Code:
+(use-package racer
+  :config
+  (setq rust-sysroot (->> "~/.cargo/bin/rustc --print sysroot"
+                          shell-command-to-string
+                          s-trim-right))
+  (setq racer-rust-src-path (f-join rust-sysroot "lib/rustlib/src/rust/src"))
+  (add-hook 'racer-mode-hook #'eldoc-mode))
+
+(use-package rust-mode
+  :config
+  (add-hook 'rust-mode-hook #'racer-mode)
+  (add-hook-before-save 'rust-mode-hook #'rust-format-buffer)
+  (define-key rust-mode-map
+    (kbd "TAB")
+    #'company-indent-or-complete-common)
+  (define-key rust-mode-map
+    (kbd "M-d")
+    #'racer-describe))
+
+(provide 'wpc-rust)
+;;; wpc-rust.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-shell.el b/emacs/.emacs.d/wpc/wpc-shell.el
new file mode 100644
index 000000000000..803a3232ef5b
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-shell.el
@@ -0,0 +1,17 @@
+;;; wpc-shell.el --- POSIX Shell scripting support -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Helpers for my shell scripting. Includes bash, zsh, etc.
+
+;;; Code:
+
+(use-package flymake-shellcheck
+  :commands flymake-shellcheck-load
+  :init
+  (add-hook 'sh-mode-hook #'flymake-shellcheck-load))
+
+(use-package fish-mode)
+
+(provide 'wpc-shell)
+;;; wpc-shell.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-terminal.el b/emacs/.emacs.d/wpc/wpc-terminal.el
new file mode 100644
index 000000000000..c232bb85a7b7
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-terminal.el
@@ -0,0 +1,70 @@
+;;; terminal.el --- My cobbled together terminal -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; My attempts at creating a sane Emacs terminal.  Most of this work was created
+;; before I discovered and fully adopted EXWM.  Prior to this, the appeal of
+;; having terminals inside of Emacs was appealing.  So appealing in fact that I
+;; was willing to work with inferior alternatives to non-Emacs terminals
+;; (e.g. `ansi-term') instead of GUI alternatives like `alacritty` because the
+;; productivity gains of having a terminal inside of Emacs might outweigh the
+;; shortcomings of that particular terminal.
+;;
+;; All of this changed, however, after discovering EXWM, since I can embed X11
+;; GUI windows inside of Emacs.  Therefore, most of this module is maintained
+;; for historical purposes.
+;;
+;; Benefits of `ansi-term':
+;; - Color scheme remains consistent between Emacs and terminal.
+;; - Same applies to my fonts.
+;;
+;; Downsides of `ansi-term':
+;; - Paging feels sluggish with programs like `cat` and `less`.
+;; - KBDs don't provide 100% coverage of what I expect from a terminal since
+;;   they were created to cooperate with Emacs.
+
+;;; Code:
+
+(require 'window)
+(require 'buffer)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: Model all open terminals within a dictionary.
+
+(defconst wpc-terminal/name
+  "wpc/terminal"
+  "The name of my terminal buffers.")
+
+(defun wpc-terminal/find-window ()
+  "Return a reference to an existing terminal window or nil."
+  (->> wpc-terminal/name
+       wpc/add-earmuffs
+       window/find))
+
+(defun wpc-terminal/find-buffer ()
+  "Return a reference to an existing terminal buffer."
+  (->> wpc-terminal/name
+       wpc/add-earmuffs
+       buffer/find))
+
+(defun wpc-terminal/find-or-create ()
+  "Find or create a terminal window."
+  (let ((buffer (wpc-terminal/find-buffer)))
+    (if buffer
+        (buffer/show buffer)
+      (ansi-term "/usr/bin/zsh" wpc-terminal/name))))
+
+;; TODO: Focus terminal after toggling it.
+(defun wpc-terminal/toggle ()
+  "Toggle a custom terminal session in Emacs."
+  (interactive)
+  (let ((window (wpc-terminal/find-window)))
+    (if window
+        (window/delete window)
+      (wpc-terminal/find-or-create))))
+
+(provide 'wpc-terminal)
+;;; wpc-terminal.el ends here
diff --git a/emacs/.emacs.d/wpc/wpc-ui.el b/emacs/.emacs.d/wpc/wpc-ui.el
new file mode 100644
index 000000000000..6ac587c46567
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpc-ui.el
@@ -0,0 +1,179 @@
+;;; wpc-ui.el --- Any related to the UI/UX goes here -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Hosts font settings, scrolling, color schemes.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'prelude)
+(require 'alist)
+(require 'themes)
+(require 'device)
+(require 'laptop-battery)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; increase line height
+(setq-default line-spacing 4)
+
+;; Ensure that buffers update when their contents change on disk.
+(global-auto-revert-mode t)
+
+;; smooth scrolling settings
+(setq scroll-step 1
+      scroll-conservatively 10000)
+
+;; clean up modeline
+(use-package diminish
+  :config
+  (diminish 'emacs-lisp-mode "elisp")
+  (diminish 'evil-commentary-mode)
+  (diminish 'flycheck-mode)
+  (diminish 'auto-revert-mode)
+  (diminish 'which-key-mode)
+  (diminish 'yas-minor-mode)
+  (diminish 'lispyville-mode)
+  (diminish 'undo-tree-mode)
+  (diminish 'company-mode)
+  (diminish 'projectile-mode)
+  (diminish 'eldoc-mode)
+  ;; This is how to diminish `auto-fill-mode'.
+  (diminish 'auto-fill-function)
+  (diminish 'counsel-mode)
+  (diminish 'ivy-mode))
+
+;; TODO: Further customize `mode-line-format' variable.
+(delete 'mode-line-modes mode-line-format)
+(delete '(vc-mode vc-mode) mode-line-format)
+
+;; disable startup screen
+(setq inhibit-startup-screen t)
+
+;; disable toolbar
+(tool-bar-mode -1)
+
+;; TODO: Re-enable `linum-mode' when I figure out why the theming is so ugly.
+;; enable line numbers
+;; (general-add-hook '(prog-mode-hook
+;;                     text-mode-hook
+;;                     conf-mode-hook)
+;;                   (enable linum-mode))
+
+;; set default buffer for Emacs
+(setq initial-buffer-choice constants/current-project)
+
+;; TODO: Re-enable this when base16-wpgtk are looking better.
+;; integration with wpgtk (in vendor directory)
+;; (require 'wpgtk-theme)
+
+;; base-16 themes to integrate with wpgtk
+;; (use-package base16-theme
+;;   :config
+;;   (require 'wpgtk)
+;;   (colorscheme/set 'base16-wpgtk))
+
+;; premium Emacs themes
+(use-package doom-themes
+  :config
+  (setq doom-themes-enable-bold t
+        doom-themes-enable-italic t)
+  (doom-themes-visual-bell-config)
+  (doom-themes-org-config))
+
+;; file browsing
+(use-package neotree
+  :config
+  (global-set-key [f8] #'neotree-toggle))
+
+;; kbd discovery
+(use-package which-key
+  :config
+  (setq which-key-idle-delay 0.25)
+  (which-key-mode))
+
+;; completion framework
+(use-package ivy
+  :config
+  (counsel-mode t)
+  (ivy-mode t)
+  (alist/set! #'counsel-M-x "" ivy-initial-inputs-alist)
+  ;; prefer using `helpful' variants
+  (progn
+    (setq counsel-describe-function-function #'helpful-callable)
+    (setq counsel-describe-variable-function #'helpful-variable))
+  (general-define-key
+   :keymaps 'ivy-minibuffer-map
+   ;; prev
+   "C-k" #'ivy-previous-line
+   "<backtab>" #'ivy-previous-line
+   ;; next
+   "C-j" #'ivy-next-line
+   "<tab>" #'ivy-next-line))
+
+(use-package ivy-prescient
+  :config
+  (ivy-prescient-mode 1)
+  (prescient-persist-mode 1))
+
+;; all-the-icons
+(use-package all-the-icons
+  :config
+  (unless (f-exists? "~/.local/share/fonts/all-the-icons.ttf")
+    (all-the-icons-install-fonts)))
+
+;; icons for Ivy
+(use-package all-the-icons-ivy
+  :after (ivy all-the-icons)
+  :config
+  (all-the-icons-ivy-setup))
+
+;; disable menubar
+(menu-bar-mode -1)
+
+;; reduce noisiness of auto-revert-mode
+(setq auto-revert-verbose nil)
+
+;; highlight lines that are over `constants/fill-column' characters long
+(use-package whitespace
+  :config
+  ;; TODO: This should change depending on the language and project. For
+  ;; example, Google Java projects prefer 100 character width instead of 80
+  ;; character width.
+  (setq whitespace-line-column constants/fill-column)
+  (setq whitespace-style '(face lines-tail))
+  (add-hook 'prog-mode-hook #'whitespace-mode))
+
+;; dirname/filename instead of filename<dirname>
+(setq uniquify-buffer-name-style 'forward)
+
+;; highlight matching parens, brackets, etc
+(show-paren-mode 1)
+
+;; hide the scroll-bars in the GUI
+(scroll-bar-mode -1)
+
+;; TODO: Learn how to properly integrate this with dunst or another system-level
+;; notification program.
+;; GUI alerts in emacs
+(use-package alert
+  :commands (alert)
+  :config
+  (setq alert-default-style 'notifier))
+
+;; TODO: Should `device/work-laptop?' be a function or a constant that gets set
+;; during initialization?
+(when (device/work-laptop?)
+  (laptop-battery/display))
+
+;; Load a theme
+(themes/set "Solarized Light")
+
+(provide 'wpc-ui)
+;;; wpc-ui.el ends here
diff --git a/emacs/.emacs.d/wpc/wpgtk.el b/emacs/.emacs.d/wpc/wpgtk.el
new file mode 100644
index 000000000000..432d82884399
--- /dev/null
+++ b/emacs/.emacs.d/wpc/wpgtk.el
@@ -0,0 +1,45 @@
+;; wpgtk.el -- A base16 colorscheme template for wpgtk.
+
+;;; Commentary:
+
+;;; Authors:
+;; Template: William Carroll <wpcarro@gmail.com>
+
+;;; Code:
+
+(require 'base16-theme)
+(require 'colorscheme)
+
+(defvar base16-wpgtk-colors
+  '(:base00 "#31213f"
+    :base01 "#E29B61"
+    :base02 "#E8C35F"
+    :base03 "#565B87"
+    :base04 "#A56785"
+    :base05 "#20A89E"
+    :base06 "#3CC2B5"
+    :base07 "#8de0e1"
+    :base08 "#629c9d"
+    :base09 "#E29B61"
+    :base0A "#E8C35F"
+    :base0B "#565B87"
+    :base0C "#A56785"
+    :base0D "#20A89E"
+    :base0E "#3CC2B5"
+    :base0F "#8de0e1")
+  "All colors for Base16 wpgtk are defined here.")
+
+;; Define the theme
+(deftheme base16-wpgtk)
+
+;; Add all the faces to the theme
+(base16-theme-define 'base16-wpgtk base16-wpgtk-colors)
+
+;; Mark the theme as provided
+(provide-theme 'base16-wpgtk)
+
+(macros/comment
+ (colorscheme/set 'base16-wpgtk))
+
+(provide 'wpgtk)
+;;; wpgtk.el ends here
diff --git a/emacs/.emacs.d/wpc/ynab.el b/emacs/.emacs.d/wpc/ynab.el
new file mode 100644
index 000000000000..7e132e20c244
--- /dev/null
+++ b/emacs/.emacs.d/wpc/ynab.el
@@ -0,0 +1,56 @@
+;;; ynab.el --- Functions for YNAB's API -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; I'm not sure what the outcome of this project is.  I'm just writing some
+;; Elisp at the moment to document some of my cursory interactions with YNAB's
+;; API.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'json)
+(require 'a)
+(require 'request)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar ynab/api-url "https://api.youneedabudget.com/v1/"
+  "The URL of the YNAB API.")
+
+(defun ynab/get-secret (name)
+  "Fetch and decrypt the secret for YNAB at NAME in the password store."
+  (password-store-get (format "%s/%s" "finance/youneedabudget.com" name)))
+
+(defvar ynab/personal-access-token
+  (ynab/get-secret "personal-access-token")
+  "My personal access token to YNAB's API.")
+
+(defvar ynab/budget-id
+  (ynab/get-secret "budget-id")
+  "The ID of my current budget on YNAB.")
+
+(defvar ynab/account-id
+  (ynab/get-secret "account-id")
+  "The ID of my current budget on YNAB.")
+
+(defun ynab/url-for-endpoint (endpoint)
+  "Return the URL for the YNAB ENDPOINT.
+This will resolve any variables in the form of {variable_name} using a prefined
+scope object."
+  (format "%s%s" ynab/api-url endpoint))
+
+(macros/comment
+ ;; TODO: Use these this map to resolve variables in an endpoint URL like
+ ;; '/budgets/{budget_id}/'.
+ '((budget_id . (ynab/get-secret "budget-id"))
+   (account_id . (ynab/get-secret "account-id")))
+ (request (ynab/url-for-endpoint "/budgets/{budget_id}/transactions")))
+
+(provide 'ynab)
+;;; ynab.el ends here
diff --git a/emacs/.emacs.d/wpc/zle.el b/emacs/.emacs.d/wpc/zle.el
new file mode 100644
index 000000000000..1b01da938456
--- /dev/null
+++ b/emacs/.emacs.d/wpc/zle.el
@@ -0,0 +1,90 @@
+;;; zle.el --- Functions to mimmick my ZLE KBDs -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; This is primarily for personal use.  The keybindings that I choose are those
+;; that feel slightly mnemonic while also not shadowing important bindings.
+;; It's quite possible that our tastes will differ here.
+;;
+;; All of these keybindings are intended to shave off milliseconds off your
+;; typing.  I don't expect these numbers to sum up to a meaningful amount.  The
+;; primary reason that I wrote this, is that it introduces a small amount of
+;; structural editing to my workflow.  I've been using these exact keybindings
+;; on the command line, and I find them subtely delightful to use.  So much so
+;; that I decided to bring them to my Emacs configuration.
+;;
+;; ZLE is the Z-shell line editor.  I have some KBDs and functions that I often
+;; want in Emacs.
+;;
+;; Usage:
+;; Consider running `(zle-minor-mode)' to run this globally.  Depending on your
+;; configuration, it could be non-disruptive, disruptive, or extremely
+;; disruptive.
+;;
+;; TODO: Consider adding (general-unbind 'insert "C-v") herein.
+
+;;; Code:
+
+;; subshell (C-j)
+(defun zle/subshell ()
+  "Insert the characters necessary to create a subshell."
+  (interactive)
+  (insert-char ?$)
+  (insert-char ?\()
+  (save-excursion
+    (insert-char ?\))))
+
+;; variable (C-v)
+(defun zle/variable ()
+  "Insert the characters to reference a variable."
+  (interactive)
+  (insert-char ?$)
+  (insert-char ?{)
+  (save-excursion
+    (insert-char ?})))
+
+;; 2x dash (C-M--)
+(defun zle/dash-dash ()
+  "Insert the characters for flags with 2x dashes."
+  (interactive)
+  (insert-char ? )
+  (insert-char ?-)
+  (insert-char ?-))
+
+;; 1x quotes (M-')
+(defun zle/single-quote ()
+  "Insert the characters to quickly create single quotes."
+  (interactive)
+  (insert-char ? )
+  (insert-char ?')
+  (save-excursion
+    (insert-char ?')))
+
+;; 2x quotes (M-")
+(defun zle/double-quote ()
+  "Insert the characters to quickly create double quotes."
+  (interactive)
+  (insert-char ? )
+  (insert-char ?\")
+  (save-excursion
+    (insert-char ?\")))
+
+(defvar zle/kbds
+  (let ((map (make-sparse-keymap)))
+    (bind-keys :map map
+               ("C-j"   . zle/subshell)
+               ("C-v"   . zle/variable)
+               ("C-M--" . zle/dash-dash)
+               ("M-'"   . zle/single-quote)
+               ("M-\""  . zle/double-quote))
+    map)
+  "Keybindings shaving milliseconds off of typing.")
+
+(define-minor-mode zle-minor-mode
+  "A minor mode mirroring my ZLE keybindings."
+  :init-value nil
+  :lighter " zle"
+  :keymap zle/kbds)
+
+(provide 'zle)
+;;; zle.el ends here