diff --git a/.nojekyll b/.nojekyll
new file mode 100644
index 0000000..e69de29
diff --git a/book.org b/book.org
index 1c439b8..8ae1681 100644
--- a/book.org
+++ b/book.org
@@ -1,273 +1,2625 @@
-#+TITLE: Bash field guide
+#+TITLE: Shell Field Guide
 #+AUTHOR: Raimon Grau
+#+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:nil arch:headline
+#+OPTIONS: author:t c:nil creator:comment d:(not "LOGBOOK") date:nil
+#+OPTIONS: e:t email:nil f:t inline:t p:nil pri:nil stat:t
+#+OPTIONS: tags:t tasks:t tex:t timestamp:t todo:t |:t
+#+EXCLUDE_TAGS: noexport
+#+KEYWORDS: bash zsh shell
+#+LANGUAGE: en
+#+SELECT_TAGS: export
 
-#+SETUPFILE: https://fniessen.github.io/org-html-themes/setup/theme-readtheorg.setup
+#+OPTIONS: html-style:nil
+#+SETUPFILE: https://fniessen.github.io/org-html-themes/org/theme-readtheorg.setup
+#+HTML_HEAD_EXTRA: <link rel="stylesheet" type="text/css" href="styles.css"/>
+
+#+OPTIONS: reveal_center:nil timestamp:nil
+#+REVEAL_THEME: black
+
+# toc:nil num:nil
 
 * Introduction
   This booklet is intended to be a catalog of tricks and techniques
-  you should be using if you're doing any sort of scripting. I'll try
-  to keep the rethoric to the very minimal because that way you can
-  enjoy the content in less time.
-
-  You probably have some amount of sh/bash/zsh in your stack that
-  probably started as 1 off scripts, and later on started growing and
-  were copypasted everywhere in your pipelines, or your coworkers use
-  for their own use (with some variations), etc. Those scripts are
-  very difficult to kill and they have a very high mutation rate.
-* shell
-  No matter if you use Linux, Mac, or Win, you should be living most
-  of the time in a shell to enjoy the content I'm gonna show
-  here. Some value comes from the automated scripts, and some other
-  value comes from the daily usage and refinement of your helper
-  functions, aliases, etc.
-
-  In general the examples here are ment to run in Bash or Zsh, which
+  you may want to use if you're doing some sort of complex
+  scripting. Some are useful in "The Real World (TM)", some are more
+  playful, and might not have such direct impact in your day-to-day
+  life. Some are pure entertainment. You'll have to judge by yourself
+  which belong to which. I'll try to keep the rhetoric to the minimum
+  to maximize signal/noise.
+
+  The git repo is at
+  https://github.com/kidd/scripting-field-guide/. Any feedback is
+  greatly appreciated. Keep in mind this is not any kind of official
+  doc. I just write MY current "state of the art" and I'll be updating
+  the contents with useful stuff I find or discover, that are not
+  widely explained in usual manuals/wikis.
+
+  You surely have some amount of sh/bash/zsh in your stack that
+  probably started as one-off scripts, and later grew and were
+  copypasted everywhere in your pipelines, repos, coworkers' ~/bin, or
+  your coworkers use for their own things (with some variations),
+  etc. Those scripts are very difficult to kill and they have a very
+  high mutation rate.
+
+* Which Shell?
+  No matter if you use Linux, Mac, or Windows, you should be living
+  most of the time in a shell to enjoy the content shown here. Some
+  value comes from running scripts, and some comes from the daily
+  usage and refinement of your helper functions, aliases, etc. in
+  interactive mode.
+
+  In general the examples here are meant to run in Bash or Zsh, which
   are compatible for the most part.
 * Level
   These examples are based on non-trivial real world code I've written
-  that I haven't seen applied in many places over the net. Some of the
-  snippets are stolen from public repos.
-* interactive
-** functions can generate aliases
-   Well, it's not lexical scope, but using aliases you can sort of
-   create a string that snapshots the procedure and then run it later.
+  using patterns I haven't seen applied in many places over the net. A
+  few of the snippets are stolen from public repos I find interesting.
+  Also, important scripting stuff might be missing if I don't feel
+  I have anything to add to the generally available info around.
+* Patterns
+** Use Shellcheck
+   First, let's get that out of the way. This is low-hanging
+   fruit. And you will get the most of this booklet by following it.
 
-   Some fun stuff:
-   - aliasgen. create an alias for each directory in ~/workspace/
-     . This is superceeded by AUTO_CD, but the trick is still cool
+   A lot of the most common errors we usually make are well known
+   ones. And in fact, we all usually fail in similar ways. Bash is
+   known for being error prone when dealing with testing variable
+   values, string operations, or flaky subshells and pipes.
+
+   Installing [[https://www.shellcheck.net/][shellcheck]] will flag many of those ticking bombs for
+   you.
+
+   No matter which editor you are using, you should be able to
+   install a plugin to do automatic checks while you're editing.
+
+   In emacs' case, the package is called [[https://github.com/federicotdn/flymake-shellcheck][flymake-shellcheck]], and a
+   quick configuration for it is:
+
+   #+begin_src elisp
+   (use-package flymake-shellcheck
+     :ensure t
+     :commands flymake-shellcheck-load
+     :init
+     (add-hook 'sh-mode-hook 'flymake-shellcheck-load))
+   #+end_src
+
+   Shellcheck is available on most distros, so it's just an =apt=,
+   =brew=, or =nix-env= away.
+
+** Booleans and Conditionals
+   In any shell, =foo && bar= will execute =bar= only if =foo=
+   succeeded. That means that =foo= returned 0. That means that to &&
+   (which you read like "and"), 0 is true. so yes. 0 is true, and
+   other values are false.
+
+** Arrays
+   Ordered list of things.
    #+begin_src bash
-   aliasgen() {
-     for i in ~/workspace/*(/) ; do
-         DIR=$(basename $i) ;
-         eval "alias $DIR='cd ~/workspace/$i'";  # probably eval is not needed
+     foo=("ls" "/tmp/")
+
+     echo ${foo[-2]}
+     echo ${foo[-1]}
+     echo ${foo[0]}
+     echo ${foo[1]}
+     echo ${foo[2]}
+
+     for i in "${foo[@]}"; do
+       echo $i
      done
-   }
-   #+end_src
-   - a. make a shortcut to the current directory.
-     #+begin_src bash
-     function a() { alias $1=cd\ $PWD; }
+
+     $foo
+     ${foo[*]}
+     ${foo[@]}
+     echo ${#foo[*]}
+     echo ${#foo[@]}
      #+end_src
 
-   - unhist. functions can create aliases, and functions can receive
-     function names (as a string).
+   Are =*= and =@= equal? [[https://stackoverflow.com/questions/2761723/what-is-the-difference-between-and-in-shell-scripts][nope]].
+
+   #+begin_src bash
+   "${foo[@]}"
+   "${foo[*]}"
+   #+end_src
+
+   #+begin_src bash
+     #!/bin/bash
+
+     main()
+     {
+       echo 'MAIN sees ' $# ' args'
+     }
+
+     main $*
+     main $@
+
+     main "$*"
+     main "$@"
+
+     ### end ###
+   #+end_src
+
+   and I run it like this:
+
+   =my_script 'a b c' d e=
+
+** Pass Arrays around
+   #+begin_src bash
+     a=('Track 01.mp3' 'Track 02.mp3')
+     myfun "${a[@]}" # pass array to a function
+     b=( "${a[@]}" ) # copy array
+   #+end_src
+
+   Read the great [[http://www.oilshell.org/blog/2016/11/06.html][Oil Shell blogpost]].
+** Slurping arrays
+   A nice way to read a bunch of elements in one go is to use
+   =readarray=.
    #+begin_src bash
-   unhist () {
-     alias $1=" $1"
+   parse_args() {
+     [[ $# -eq 0 ]] && die "Usage: $0 <version>"
+     version="$1"
+     local version_split=$(echo $version | tr '.' '\n')
+     readarray -t version_array <<< "$version_split"
+
+     if [[ -z ${version_array[3]} ]]; then
+       die "not enough version numbers"
+     fi
    }
-   unhist unhist
-   unhist grep
-   unhist rg
+   #+end_src
+
+   Even nicer would be to use IFS so we'd be able to split in one go.
+
+   #+begin_src bash
+     IFS=. read -a ver <<<"1.23.1.0"
+     echo ${ver[0]}
+     echo "next/${ver[0]}.${ver[1]}.x.x"
+   #+end_src
+
+   Or, use it in a destructuring fashion:
+   #+begin_src bash
+    get_nix_version_parts(){
+      local major minor patch
+      # shellcheck disable=SC2034,SC2162
+      IFS="." read major minor patch < <(get_nix_version)
+      local -p
+    }
+
+    $ get_nix_version_parts
+    major=2
+    minor=3
+    patch=4
+   #+end_src
+   https://news.ycombinator.com/item?id=24408318
+** Array slices
+
+   you can slice an array like this:
+
+   #+begin_src bash
+     a=(a b c d e f g)
+     echo "${a[@]:1}"  # tail of array
+     echo "${a[@]:1:2}"  # from that, take 2 elements
+   #+end_src
+
+   This is a [[https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html][parameter expansion]], same as =${a/foo/bar}= and similar
+   replacements. As such, The =$@= and =$*= are treated a bit
+   differently.
+
+   Look at =${parameter:offset:length}= in the parameter expansion
+   bash manual and be amazed by the specialcasing :).
+
+   This concrete case is when the parameter is an indexed array name
+   subscripted by '@' or '*'.
+
+   Don't ask me why, but when the array is =$@=, it seems that it
+   behaves a bit differently. It's 'explained' in that same part of
+   the docs.
+
+   #+begin_src bash
+     a=(a b c d e f g)
+    foo() {
+     echo "${@:2}"  # tail of array
+     echo "${@:2:2}"  # from that, take 2 elements
+    }
+    foo a b c d
+    foo "${a[@]}"
+   #+end_src
 
-   noglobber() {
-       alias $1="noglob $1"
+** Read lines from file
+   The =read= command we used just above is part of the usual idiom to
+   read a file line by line.
+
+   #+begin_src bash
+     while read -r line; do
+       echo $line
+     done < /tmp/file.txt
+   #+end_src
+
+   More related info in the [[https://mywiki.wooledge.org/BashFAQ/001][BashFAQ001]]. But it's very rare the case
+   where I need to iterate a file line by line.
+
+** Assign to $1,$2,$3...
+   =set --= can be used as an incantation to assign to the positional
+   parameters. Let me show you.
+
+   #+begin_src bash
+     set -- a b c
+     echo $1 $2 $3
+     echo $@
+   #+end_src
+
+   See? here's how to "unshift" a parameter to the current arg list:
+
+   #+begin_src bash
+     set -- "injected" "$@"
+   #+end_src
+
+** Functions
+   Functions are functions. They receive arguments, and they return a
+   value.
+
+   The special thing about shell functions is that they also can use
+   the file descriptors of the process. That means that they "inherit"
+   STDIN, STDOUT, STDERR (and maybe more).
+
+   Use them.
+
+   Another point is that function names can be passed as parameters,
+   because they are passed as strings, but you can call them inside as
+   functions again. Maybe they are better than you [[https://news.ycombinator.com/item?id=29058140][think.]]
+
+   #+begin_src bash
+   f() {
+     $1 hi
    }
-   noglobber http
-   noglobber curl
-   noglobber git
 
+   f echo
+   f touch # will create a file 'hi'
    #+end_src
-   - Problem: Combination of 2 of those doesn't work.
-     Solution:
 
-     #+begin_src bash
-     alias-to() {
-       alias $1 | sed -e "s/.*='//" -e "s/'\$//"
-     }
+   #+RESULTS:
+   : hi
 
-     aliasappend() {
-       local cmd
-       if alias $1 >/dev/null; then
-         cmd=$(alias-to $1)
-       else
-         cmd=$1
-       fi
-       echo $cmd
-     }
+** Variables
+   By default variables are global, to a file. No matter if you assign
+   them for the first time inside a function, or at the top level.
+   #+begin_src bash
+   foo=3
+   bar=$foo
+   f() {
+     echo $bar
+   }
+   f
+   #+end_src
 
-     muter() {
-       local c
-       c=$(aliasappend $1)
-       alias $1="$c >/dev/null"
-     }
+   #+RESULTS:
+   : 3
 
-     #+end_src
-* bash
-** use shellcheck
-* zsh
-** global aliases make a forthy shell
-** examples of global aliases
-   - lspdf -tr TL P XA evince
-   - docker exec -u root -ti $(docker ps -q H1) bash
-** pass commands around
    #+begin_src bash
-   compare_outputs() {
-     export DRY_RUN=1
-     $@ 2>/tmp/1.out
-     git checkout -
-     $@ 2>/tmp/2.out
-     git checkout -
-     echo "diffing"
-     diff /tmp/1.out /tmp/2.out
+   f() {
+     bar=1
+   }
+   f
+   echo $bar
+   #+end_src
+
+   #+RESULTS:
+   : 1
+
+   You make a variable local to a function with =local=. Use it as
+   much as you can (kinda obvious).
+   #+begin_src bash
+   myfun() {
+     local bar
+     bar=3
+     echo $bar
    }
-   # noglob compare_outputs ./release.sh -u 1 -k 1 -p rhel:6 -v 1 -e -R 'internal-preview'
 
-   # extra tricky
-   alias -g SPLIT='| tr " " "\n" '
-   alias -g FORI='| while read i ; do '
-   alias -g IROF='; done '
+   bar=4
+   echo $bar
+   myfun
+   echo $bar
+   #+end_src
+
+   #+RESULTS:
+   | 4 |
+   | 3 |
+   | 4 |
+** Variable/Parameter Expansions
+   They offer some variable manipulations using shell only, not having
+   to create another process =sed,awk,perl=.
+
+   #+begin_src bash
+     v=banana
+     # substitute one
+     echo ${v/na/NA}   # baNAna
+
+     # substitute many
+     echo ${v//na/NA}  # baNANA
+
+     # substitute from the start (think ^ in PCRE)
+     echo ${v/#ba/NA}  # NAnana
 
-   echo "ga internal-preview rc1 rc2" SPLIT FORI
-      noglob compare_outputs ./release.sh -u 1 -k 1 -p rhel:8 -v 1 -e -R "$i"
-   IROF
+     # substitute from the end
+     echo ${v/%na/NA}  # banaNA
+
+     # Capitalize
+     echo ${v^}  # Banana
+
+     # Uppercase
+     echo ${v^^}  # BANANA
    #+end_src
 
-* debugging
-** adding =bash= to a script to debug
-* patterns
-** append options in an array during the logic of the program
-   And splat them in the cli of the command you're throwing (docker run?)
-** trap
-   - trap "rm $variable"
-** debug by introducing a 'bash'
-   insert =bash=
-** debug with set -xa
-   optargs "V" option; do
-   case $option in
-   V)
-     set -xa
-     ;;
-** DRY_RUN
+   Take a read on https://tldp.org/LDP/abs/html/manipulatingvars.html
+   and
+   https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
+   for more details.
+
+   And a nice non-obvious trick from here is to prefix or suffix a
+   variable string:
+
    #+begin_src bash
-   if [[-n $DRY_RUN ]]; then
-     curl () {
-       echo curl $@
-     }
-   fi
+     v=banana
+     echo ${v/%/na}   # bananana
+     echo ${v/#/na}   # nabanana
    #+end_src
-   use =command curl= to force the command, not the alias or anything
-** structure the app like a normal app
-   Shellscripts are thought as quick one-off programs, but the truth
-   is that they tend to be useful and sticky, so you better write them
-   from the start as if it would be permanent.
-*** Fail Fast
-    - https://dougrichardson.us/2018/08/03/fail-fast-bash-scripting.html
-*** Template
-    Bash is extremely permissive in what it allows to be coded and
-    ran. By default, failures do not make the program exit or throw an
-    exeption (no exceptions here).
-
-    A way to improve the defaults, is setting a bunch of flags that
-    make the script stricter, so it fails on many red flag situations
-    you'd want to stop anyway because something went wrong.
-    #+begin_src bash
-    #!/usr/bin/env bash
-    set -eEuo pipefail
-    shopt -s inherit_errexit
-
-    main() {
-      parse_args()
-      validate_args()
-      do_things()
-      cleanup()
-    }
 
-    main "$@"
-    #+end_src
-** make steps of the process composable
+   And a less obvious trick is to prefix every element of an array
+   with a fixed string:
+   #+begin_src bash
+     local arr=(var1=1 var2=2)
+     echo ${arr[*]/#/"--env "}
+   #+end_src
+
+   This will produce =--env var1=1 --env var2=2=.  Super useful to be
+   combined when building flags for docker.
+
+   Another nice trick is a portable =realpath $PWD= with =${0%/*}=,
+   which I found in [[https://github.com/picolisp/pil21/blob/master/vip][picolisp's vip]]:
+
+   #+begin_src bash
+     #!/bin/sh
+     exec ${0%/*}/bin/picolisp ${0%/*}/lib.l @bin/vip "$@"
+   #+end_src
+
+   =${0%/*}/bin/picolisp= will replace keep the path of the current
+   script and append =/bin/picolisp=. A cool way to get a realpath.
+
+** Conditional Expansion
+
+   #+begin_src bash
+   local  foo=${var:-${default:-}}
+   local  foo=${var:+&key=var}
+   #+end_src
+
+** Interpolation
+   We previously saw that functions can be passed around as strings,
+   and be called later on.
+
+   Something that might not be obvious is that the string can be
+   created from shorter strings, and that allows for an extra
+   flexibility, that comes with its own dangers, but it's a very
+   useful pattern to dispatch functions based on user input or
+   function outputs.
+   #+begin_src bash
+   l=l
+   s=s
+   $l$s .
+   #+end_src
+
+   #+RESULTS:
+   | book.html  |
+   | book.html~ |
+   | book.org   |
+   | readme.org |
+
+** dispatch functions using args
+   A nice usage of the previous technique is using user input as a
+   dispatching method.
+
+   You've probably seen this pattern already:
+
    #+begin_src bash
    while [[ $# -gt 0 ]]; do
-    key="$1"
-    $key  # eval $key as a function
-    shift
+
+   case $1 in
+     foo)
+       foo
+       ;;
+     *)
+       exit 1
+       ;;
+   esac
+   shift
    done
    #+end_src
-** use $@ when you can
+
+   And it is useful for its own good, and flexible.
+
+   But for some simpler cases, we can dispatch based on the variable
+   itself:
+
+   #+begin_src bash
+   cmd_foo() {
+    do-something
+   }
+
+   cmd_$1
+   #+end_src
+
+   The problem with this is that in case we supply a =$1= that doesn't
+   map to any =cmd_$1= we'll get something like
+
+   #+begin_src bash
+   bash: cmd_notexisting: command not found
+   #+end_src
+
+** command_not_found_handle
+   Here's a detail on a kinda obscure bash (only bash) feature.
+
+   You can set a hook that will be called when bash tries to run a
+   command and it doesn't find it.
+
    #+begin_src bash
+   command_not_found_handle() {
+     echo "$1 is not a correct command. Cmds allowed:"
+     echo "$(typeset -F | grep cmd_ | sed -e 's/.*cmd_/cmd_/')"
+   }
+
+   cmd_foo() {
+     echo "foo"
+   }
 
-   compare_outputs() {
-     export DRY_RUN=1
-     $@ 2>/tmp/1.out
-     git checkout -
-     $@ 2>/tmp/2.out
-     git checkout -
-     echo "diffing"
-     diff /tmp/1.out /tmp/2.out
+   cmd_baz() {
+     echo "baz"
    }
+   cmd_bar
+   #+end_src
 
-   compare_outputs ./release.sh -u 1 -k 1 -p rhel:6 -v 1 -e -R 'internal-preview'
+   You can unset the function =command_not_found_handle= to go back to
+   the normal behavior.
 
-   # extra tricky
-   alias -g SPLIT='| tr " " "\n" '
-   alias -g FORI='| while read i ; do '
-   alias -g IROF='; done '
+** Return Values for Conditionals
+   =if= 's test condition can use the return values of
+   commands. That's a known thing, but a lot of code you see around
+   relies on =[[]]= to test the return values of commands/functions
+   anyway.
 
-   echo "ga internal-preview rc1 rc2" SPLIT FORI
-     compare_outputs ./release.sh -u 1 -k 1 -p rhel:8 -v 1 -e -R "$i"
-   IROF
+   #+begin_src bash
+   if echo "foo" | grep "bar" ; then
+     echo "found!"
+   fi
    #+end_src
-   - https://www.oilshell.org/blog/2017/01/13.html
-** source files
-   it's a "require"
-** use files as a lib
-   #+begin_src bash
-    # Allow sourcing of this script
-    if [[ $(basename "$(realpath "$0")") == "package.sh" ]]; then
-      setup
-      parse_args "$@"
-
-      # Only load silent-run functions if silent execution
-      # assure-not-messy-101
-      if [[ $VERBOSE == 0 ]]; then
-        BUILD_LOG=${BUILD_LOG:-$(mktemp /tmp/kong-distributions-build.XXXXX)}
-        source $LOCAL_PATH/silent-run.sh
-      fi
 
-      main
-    fi
+   This is much clearer than
+   #+begin_src bash
+   if [[ ! -z $( echo "foo" | grep "bar") ]]; then
+     echo "found!"
+   fi
    #+end_src
-** Use tempfile and tmpdirs for EVERYTHING
-   and trap on_exit
-** array of callbacks on_exit
+
+   As easy and trivial as it seems, this way of thinking pushes you
+   forward to thinking about creating smaller functions that check the
+   conditions and =return= 0 or non 0. It's syntactically smaller, and
+   usually makes you play by the rules of the commands, more than just
+   finding your way around the output strings.
+
+   #+begin_src bash
+   if less_than $package "1.3.2"; then
+     die "can't proceed"
+   fi
+   #+end_src
+
+** set variable in an "if" test
+   Usual pattern to capture the output of a command and branch
+   depending on its return value is:
    #+begin_src bash
+     res="$(... whatever ...)"
+     if [ "$?" -eq 0 ]; then ...
+                             ...
+     fi
+   #+end_src
 
-   ON_EXIT=()
-   EXIT_RES=
+   Well, you can test the return value AND capture the output at the
+   same time!
 
-   function on_exit_fn {
-     EXIT_RES=$?
-     for cb in "${ON_EXIT[@]}"; do $cb || true; done
-     return $EXIT_RES
-   }
+   #+begin_src bash
+     if res="$(...)"; then
+       ...
+     fi
+   #+end_src
+
+   Unfortunately, it doesnt' work with =local=, so you can't be
+   defining a local var in the same line. So, the variable is either
+   global, or you spent a line to declare it local before. Still, I
+   think I prefer to have a line to declare the variable as local
+   rather than having explicit =$?='s around.
+   #+begin_src bash
+     local var1
+     if var1=$(f); then
+       echo "$var1"
+     fi
+   #+end_src
+   Ref: https://news.ycombinator.com/item?id=27163494
+
+** Do work on loop conditions
+   I've not seen it used a lot (and there might be a reason for it,
+   who knows), =while= conditions are just plain commands, so you can
+   put other stuff than =[]/[[]]/test= there.
+
+   Heres's an idiomatic way to iterate through all the arguments of a
+   function while consuming the =$*= array.
+
+   #+begin_src bash
+   while(($#)) ; do
+     #...
+     shift
+   done
+   #+end_src
+
+   And here's a pseudo-repl that keeps shooting one-off commands. This
+   will keep shooting =tr= commands to whatever strings you give it,
+   with the usual rlwrap goodies.
+
+   #+begin_src bash
+   while rlwrap -o -S'>> ' tr a-z A-Z ; do :; done
+   #+end_src
+
+   Note: =:= is a nop builtin in bash.
+** One Branch Conditionals
+   The usual conditionals one sees everywhere look like =if=.
+   #+begin_src bash
+   if [[ some-condition ]]; then
+     echo "yes"
+   fi
+   #+end_src
 
-   trap on_exit_fn EXIT SIGINT
+   This is all good and fine, but in the same vein of using the least
+   powerful construct for each task, it's nice to think of the one way
+   conditionals in the form of =&&= and =||= as a way to explicitly
+   say that we don't want to do anything else when the condition is
+   not met. It's a hint to the reader.
 
-   function on_exit {
-     ON_EXIT+=("$@")
+   #+begin_src bash
+   some-condition || {
+      echo "log: warning!"
    }
 
+   other-condition && {
+      echo "log: all cool"
+   }
    #+end_src
-** pass flags as a splatted array
-** explore what passes through a pipe with
-   - https://stackoverflow.com/questions/17983777/shell-pipe-to-multiple-commands-in-a-file
-   tee >(some_command) |
-** inherit_errcode
-* links
-  - Gary Bernhardt. The Unix Chainsaw
-  - https://news.ycombinator.com/item?id=23765123
-  - https://medium.com/@joydeepubuntu/functional-programming-in-bash-145b6db336b7
-  - https://www.youtube.com/watch?v=yD2ekOEP9sU
-* from shell to lisp and everything in between
-  - https://github.com/oilshell/oil
-  - https://www.eigenbahn.com/2020/07/08/painless-emacs-remote-shells
-  - spencertipping
-  - rash
-  - zsh
-
-* make scripts compatible between them
-** create scripts that replace shell commands and do the same.
-   to be able to run a zsh script with noglobs in bash, here's
-   =~/bin/noglob=.
+
+   This conveys the intention of doing something *just* in one case,
+   and that the negation of this is not interesting at all. There's a
+   big warning you have to be aware of. The same as with lua's
+   =... and .. or ..=, bash =||= and =&&= are not interchangeable for
+   =if...else...end=. [[https://mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3][BashWiki]] has an explanation why, but, the same
+   as in Lua's case, if the "then" part returns false, the else will
+   run.
+
+   There are lots of references to this, but I like this recent post
+   where it explains it for arrays in higher level languages like ruby:
+   https://jesseduffield.com/array-functions-and-the-rule-of-least-power/
+
+   An extended article of this kind of conditionals can be found [[https://timvisee.com/blog/elegant-bash-conditionals/][here]].
+** pushd/popd
+   pushd and popd are used to move to some directory and go back to it
+   in a stack fashion, so nesting can happen and you never lose
+   track. The problem is that it still is on you to have a =popd= per
+   =pushd=.
    #+begin_src bash
-   #!/usr/bin/env bash
-   $*
+   pushd /tmp/my-dir
+     echo $PWD
+   popd
+   #+end_src
+
+   Here's an alternative way, that at least makes sure that you close
+   all pushd with a popd.
+
+   Starting a new shell and cd-ing , will make all commands in that
+   subshell be in that directory, and will come back to the old
+   directory after closing the new spawned shell.
+
+   #+begin_src bash
+     (cd /tmp/my-dir
+       ls
+     )
+   #+end_src
+
+   Remember to =inherit_errexit= or =set -e= inside the subshell if
+   you need. That's a very easy trap to fall into.
+
+** wrap functions
+   Bash can't pass blocks of code around, but the alternative is to
+   pass functions.  More on that later.
+
+   #+begin_src bash
+     mute() {
+       "$@" >/dev/null
+     }
+
+     mute pushd /tmp/foobar
+   #+end_src
+** use [[
+   Unless you want your script to be POSIX compliant, use =[[= instead
+   of =[=.  =[= is a regular command. It's like =ls=, or =true=. You can
+   check it by searching for a file named =[= in your path.
+
+   Being a normal command it always evaluates its params, like a
+   regular function. On the other hand though, =[[= is a special bash
+   operator, and it evaluates the parameters lazily.
+
+   #+begin_src bash
+
+     # [[ does lazy evaluation:
+     [[ a = b && $(echo foo >&2) ]]
+
+     # [ does not:
+     [ a = b -a "$(echo foo >&2)” ]
+     #+end_src
+   Ref: https://lists.gnu.org/archive/html/help-bash/2014-06/msg00013.html
+
+** eval?
+   When you have mostly small functions that are mostly pure, you
+   compose them like you'd do in any other language.
+
+   In the following snippet, we are in a release script. Some step
+   builds a package inside a docker container, another step tests a
+   package already built.
+
+   A nice way to build ubuntus, for example, is to add an ARG to the
+   Dockerfile so we can build several ubuntu versions using the same
+   file.
+
+   It'd look like this:
+   #+begin_src Dockerfile
+     ARG VERSION
+     FROM ubuntu:$VERSION
+
+     RUN apt-get ...
+     ...
+   #+end_src
+
+   We build that image and do all the building inside it, mounting a
+   volume shared with our host, so we can extract our =.deb= file
+   easily.
+
+   After that, to do some smoke tests on the package, the idea is to
+   install the =.deb= file in a fresh ubuntu image.
+
+   Let's pick the same base image we picked to build the package.
+   #+begin_src bash
+     # evaluate the string "centos:$VERSION" (that comes from
+     # centos/Dockerfile) in the current scope
+     # DISTRO is ubuntu:18.04
+     local VERSION=$(get_version $DISTRO) # VERSION==18.04
+     run_test "file.deb" "$(eval echo $(awk '/^FROM /{print $2; exit}' $LOCAL_PATH/$(get_dockerfile_for $DISTRO)))" # ubuntu:18.04
+   #+end_src
+
+   The usage of eval is there to interpolate the string that we get
+   from the =FROM= in the current environment.
+
+   WARNING: You know, anything that uses =eval= is dangerous per
+   se. Do not use it unless you know very well what you're doing AND
+   the input is 100% under your control. Usually, more restricted
+   commands can achieve what you want to do. In this particular case,
+   you could use =envsubst=, or just manually replace =$\{?VERSION\}?=
+   in a sed.
+
+   #+begin_src bash
+     test_release "$PACKAGE_PATH" $(awk '/^FROM /{print $2; exit}' $LOCAL_PATH/$(get_dockerfile_for $DISTRO) | sed -e "s/\$VERSION/$VERSION/")
+   #+end_src
+
+   Yet another way is using [[https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html][shell parameter expansions.]]
+   #+begin_src bash
+
+     var1=value
+     echo 'this is $var1' >/tmp/f.txt
+     f=$(cat /tmp/f.txt)
+     echo "${f}"  # this is $var1
+     echo "${f@P}"  # this is value
+   #+end_src
+
+** pass commands around
+   This one uses [[*DRY_RUN][DRY_RUN]]. While refactoring a script that does some
+   curls, we want to make sure that our refactored version does the
+   exact same calls in the same order.
+
+   #+begin_src bash
+     compare_outputs() {
+       export DRY_RUN=1
+       git checkout b1
+       $@ 2>/tmp/1.out
+       git checkout b2
+       $@ 2>/tmp/2.out
+       echo "diffing"
+       diff /tmp/1.out /tmp/2.out
+     }
+     compare_outputs ./release.sh -p rhel:6 -R 'internal-preview'
+   #+end_src
+
+   First we create a function =compare_outputs=, that gets a command
+   to run as parameters. The function will run it once, redirecting
+   the standard error to a file =/tmp/1.out=.
+
+   Then, it checks out the branch that contains our refactored
+   version, and will run the command again, redirecting standard error
+   to =/tmp/2.out=, and will diff the two outputs.
+
+   In case there's a difference between the two, =diff= will output
+   them, and the function will return the non-zero exit value of
+   diff. If everything went fine, =compare_outputs= will succeed.
+
+   Now that we know that for these inputs the command runs fine, we
+   want to find out if it works for other types of releases, not only
+   internal-preview.
+
+   Here I'm using zsh's global aliases to give a much more fluid
+   interface to the commands, but you can use the regular while/for
+   loops:
+
+   #+begin_src shell
+     alias -g SPLIT='| tr " " "\n" '
+     alias -g FORI='| while read i ; do '
+     alias -g IROF='; done '
+
+     set -e
+     echo "ga internal-preview rc1 rc2" SPLIT FORI
+        noglob compare_outputs ./release.sh -p rhel:8 -R "$i"
+     IROF
    #+end_src
+
+   So, combining the two, we can have a really smooth way of iterating
+   over the possibilities, without really messing into the details of
+   loops.
+
+   WARNING: This approach is not robust enough to put it anywhere in
+   production, but to write quick one off scripts is a
+   killer. Experimenting in a shell and creating tools and 2nd order
+   tools to make interaction faster builds a language that grows on
+   you, and keeps improving your toolbelt.
+
+** The Toplevel Is Hopeless
+   Shellscripts are thought as quick one-off programs, but when they
+   are useful, they are sticky, so you better write them from the
+   start as if it would be permanent. The upfront cost is very low
+   anyway. Structure the script like a regular app.
+
+   Bash is extremely permissive in what it allows to be coded and
+   ran. By default, failures do not make the program exit or throw an
+   exception (no exceptions). And for some reason, the common
+   usage of shellscripts is to put everything in the top level. Don't
+   do that. Do the least possible things in the toplevel.
+
+   A way to improve the defaults, is setting a bunch of flags that
+   make the script stricter, so it fails on many situations you'd
+   want to stop anyway because something went wrong.
+   #+begin_src bash
+     #!/usr/bin/env bash
+     set -eEuo pipefail
+     shopt -s inherit_errexit
+
+     main() {
+       parse_args
+       validate_args
+       do_things
+       cleanup
+     }
+
+     main "$@"
+   #+end_src
+
+   Ref: https://dougrichardson.us/2018/08/03/fail-fast-bash-scripting.html
+
+   Although... [[http://mywiki.wooledge.org/BashFAQ/105][Why doesn't set -e do what I expected?]]
+
+** Check your deps
+   Giving useful information to the users will help them using the
+   script, and you debugging it. Script dependencies is a common use
+   case that we'll do it in a nice way.
+
+   #+begin_src bash
+     deps() {
+       for dep in "$@"; do
+         mute command -v "$dep" || die "$dep dependency missing"
+       done
+     }
+
+     main() {
+       deps jq curl
+       # ...
+     }
+   #+end_src
+
+** source files
+   =source= is like =require= or =import= in some programming
+   languages. It evaluates the sourced file in the context of the
+   current script, so you get all definitions in your environment.
+
+   It's simple, but it helps you get used to modularize your code into
+   libraries.
+
+   Be careful, it's very rudimentary, and it will be overwriting old
+   vars or functions if names clash. There's no namespacing happening
+   there.
+
+   #+begin_src bash
+     source file.sh
+
+     # the same
+     . file.sh
+   #+end_src
+
+** Use Scripts as a Libs
+   A python-inspired way of using scripts as loadable libraries is to
+   check whether the current file was the one that was called
+   originally or it's being just sourced.
+
+   Again, no side effects in load time makes this functionality
+   possible. otherwise, you're on your own.
+   #+begin_src bash
+     # Allow sourcing of this script
+     if [[ $(basename "$(realpath "$0")") == "$(basename "${BASH_SOURCE}")" ]]; then
+       setup
+       parse_args "$@"
+       main
+     fi
+   #+end_src
+** Tmpfiles Everywhere
+   Your script is not going to run alone. Don't assume paths are
+   fixed or known.
+
+   CI/CD Pipelines run many jobs in the same node and files can start
+   clashing.
+
+   Make use of =$(mktemp -d /tmp/foo-bar.XXXXX)=.  If you have to patch a
+   file, do it in a clean fresh copy. Don't modify files in old paths
+
+   If you HAVE TO modify paths, do it idempotently.  But really, don't do it.
+
+   #+begin_src bash :eval no
+     git_clone_tmp() {
+       local repo=${1:?repo is required}
+       local ref=${2:?ref is required}
+       tmpath=$(mktemp -d "/tmp/cloned-$repo-XXXXX")
+       on_exit "rm -rf $tmpath"
+       git clone -b ${ref} $repo $tmpath
+     }
+   #+end_src
+
+   CAVEAT: You have to manually delete the directory if you want it cleaned.
+
+   Here's an article with very good advice on [[https://www.netmeister.org/blog/mktemp.html][tempfiles]].
+** Cleanup tasks with trap
+   =trap= is used to 'subscribe' a callback when something happens.
+   Many times it's used on exit. It's a good thing to cleanup tmpdirs after your script
+   exits, so you can use the output of =mktemp -d= and subscribe a cleanup
+   function for it.
+
+   #+begin_src bash
+     on_exit() {
+       rm -rf $1
+     }
+     local tmpath=$(mktemp -d /tmp/foo-bar.XXXXX)
+     trap "on_exit $tmpath" EXIT SIGINT
+   #+end_src
+
+** array of callbacks on_exit
+   Level up that pattern, we can have a helper to add callbacks to run
+   on exit. Get used to these kind of patterns, they are super
+   powerful and save you lots of manual bookkeeping.
+
+   #+begin_src bash
+
+     ON_EXIT=()
+     EXIT_RES=
+
+     function on_exit_fn {
+       EXIT_RES=$?
+       for cb in "${ON_EXIT[@]}"; do $cb || true; done
+       return $EXIT_RES
+     }
+
+     trap on_exit_fn EXIT SIGINT
+
+     function on_exit {
+       ON_EXIT+=("$@")
+     }
+
+     local v_id=$(docker volume create)
+     on_exit "docker volume rm $v_id"
+     # Use your v_id knowing that it'll be available during your script but
+     # will be cleaned up before exiting.
+   #+end_src
+
+** stacktrace on error
+   Here's a nice helper for debugging errors in bash. In case of non-0
+   exit, it prints a stacktrace.
+   #+begin_src bash
+      set -Eeuo pipefail
+      trap stacktrace EXIT
+      stacktrace() {
+          rc="$?"
+          if [ $rc != 0 ]; then
+              printf '\nThe command "%s" triggerd a stacktrace:\n' "$BASH_COMMAND"
+              for i in $(seq 1 $((${#FUNCNAME[@]} - 2))); do
+                j=$((i+1));
+                printf '\t%s: %s() called in %s:%s\n' "${BASH_SOURCE[$i]}" "${FUNCNAME[$i]}" "${BASH_SOURCE[$j]}" "${BASH_LINENO[$i]}";
+              done
+          fi
+      }
+
+   #+end_src
+   ref: https://news.ycombinator.com/item?id=26644110
+** Dots and colons allowed in function names!
+   A way to split the namespace is to have libs define functions with
+   their own namespace.
+
+   I've gotten used to use dots or colons as namespace separator.
+   #+begin_src bash
+     semver.greater() {
+      # ...
+     }
+   #+end_src
+   or
+   #+begin_src bash
+     semver:greater() {
+      # ...
+     }
+   #+end_src
+** make steps of the process as composable as possible by using "$@"
+   By using =$@= to pass commands as parameters around you can get to
+   a degree of composability that allows for a nice chaining of
+   commands.
+
+   Here's a very simple version of =watch=. See how you can =every 2
+   ls -la=. I think that style is called Bernstein Chaining. But I'm
+   not sure if it's exactly the same. It also looks like currying or
+   partial evaluation to me if you squint a little bit.
+
+   #+begin_src bash
+     every() {
+        secs=$1
+        shift
+        while true; do
+          "$@"
+          sleep $secs;
+        done
+      }
+   #+end_src
+
+
+   As you know by now, bash doesn't pass blocks of code around, but
+   the alternative is to pass function names.
+
+   #+begin_src bash
+     mute() {
+       $@ >/dev/null 2>/dev/null
+     }
+     mute ls
+   #+end_src
+
+   So now we can create the most useless command composition ever:
+
+   #+begin_src bash
+     every 1 mute echo hi
+     #or
+     mute every 1 echo hi
+   #+end_src
+
+   For the particular redirection problem, another option is to use
+   aliases. Redirects can be written anywhere on your CLI (not just at
+   the end), so the following will work using a plain alias:
+   #+begin_src bash
+     alias mute='>/dev/null 2>/dev/null'
+     mute ls
+   #+end_src
+
+
+
+   - https://www.oilshell.org/blog/2017/01/13.html
+** do_times/foreach_*
+   shellscripts are highly side-efffecty, and even though the scoping
+   of variables is not very empowering, you can get a limited amount
+   of decomposition of loops by passing function names.
+
+   This is a lame example, but I hope it shows the use case, it allows
+   you to group already existing functions while taking advantage of a
+   fixed looping iterator, and leaving traces of the current loop vars
+   in the global "variable" environment.
+
+   #+begin_src bash
+     create_user() {
+       uname="u$1" # leave uname in the global env so later functions see it
+       http :8080/users name="$uname"
+     }
+
+     create_pet() {
+       pname="p$1"
+       http :8080/users/$uname/pets name="$pname"
+     }
+
+     create_bundle() {
+       create_user $1
+       create_pet $1
+     }
+
+     do_times() {
+       local n=$1; shift
+       for i in $(seq $n); do
+         "$@" $i
+       done
+     }
+
+     do_times 15 create_bundle
+   #+end_src
+
+   A bit more complex is runnning a command to every repo in an org:
+
+   #+begin_src bash
+     run_tests() {
+       ./ci/test.sh
+     }
+
+     foreach_repo_with_index() {
+       local counter=0
+       local repos=$(http https://api.github.com/users/$1/repos)
+       shift
+       for entry in $(echo $repos | jq -r '.[].git_url'); do
+         (git_clone_tmp $entry master
+          cd $tmpath
+          "$@" $counter $entry
+         )
+         ((counter=counter+1))
+       done
+     }
+
+     foreach_repo_with_index kidd run_tests
+   #+end_src
+
+** <(foo) and >(foo)
+   Some commands ask for files as inputs. And sometimes you have that
+   file, but sometimes you're only creating that file to pass it to
+   the command.  In those cases, creating temporary files is not
+   necessary if you use =<(cmd)=. Here's a way to diff the output of 2
+   commands without putting them in a temporary file.
+
+   #+begin_src bash
+     diff <(date) <(date)
+     diff <(date) <(sleep 1; date)
+   #+end_src
+
+   The same happens with outputs. Commands that ask you for a
+   destination file. You can trick them by using =>(command)= as a
+   file. A nice trick is to use =>(cat)= to know what's going on
+   there. Also useful to send stuff to the clipboard =>(xclip)= before
+   running something on the output.
+
+   What the shell does in those cases is to bind a file descriptor of
+   the process created inside =< or >= to the first process.
+
+   You can experiment with those using commands like =echo <(pwd)=.
+
+   In Zsh you can use =m-x expand-word= to see the file descriptors
+   being expanded.
+
+   A way to peek into a huge pipe is to =tee >(cat)=
+
+** Modify behavior by linking files
+   Imagine you want to remove the =.bash_history= file and not record
+   history of commands.  You don't can't avoid bash to write to that
+   file, but what you can do is to link =.bash_history= to
+   =/dev/null=. That way, bash will keep appending things to the
+   expected output file, without noticing that it is really writing to
+   =/dev/null=. The trick is to use: =ln -sf /dev/null .bash_history=.
+
+** Modify a file on the fly, without changing it on disk
+   If you want to use a slightly modified version of a file for a
+   single use, and then throw it away, consider the following:
+
+   Everywhere that you should pass =file=, you could pass =<(cat
+   orig_file)= instead, because they have the same content, only the
+   second version is ephemeral.
+
+   If you want a modified version of it, we can attach more commands
+   to the subshell.
+
+   Example of a command that reuses your =~/.psqlrc= and adds a line
+   in the end to make the session read-only.
+
+   #+begin_src bash
+     ropsql() {
+       PSQLRC=<(
+         cat ~/.psqlrc &&
+         echo 'set session characteristics as transaction read only;') \
+       psql "$@"
+     }
+   #+end_src
+
+** Use xargs
+   Continuing with other ways of plumbing commands into other
+   commands, there's =xargs=. Some commands work seamlessly with
+   pipes, by taking inputs from stdin and printing to stdout.  But
+   some others like to work with files, and they ask for their
+   parameters in their args list. For example, =evince=. It wouldn't
+   be even expected to cat a pdf and pass it to evince through
+   stdin.
+
+   In general, to convert from this pattern: =cmd param= to =echo
+   param| cmd=, xargs can be helpful. Look at its man page to know how
+   to split or batch args in multiple =cmd= calls.
+
+   Xargs is helpful for parallelizing work. You should look at its man
+   page, but just know it can help in running parallel processes
+   (check =-P= in its man).
+
+   Other tips on this great [[https://www.oilshell.org/blog/2021/08/xargs.html][Guide to xargs]].
+
+** xargs + paste
+   =paste= can be thougth as =zip=, interleaving the outputs of
+   several commands line by line.
+
+   #+begin_src bash
+     paste <(./cmd1) <(./cmd2) | xargs -L1 ./cmd3
+   #+end_src
+
+   Ref: https://news.ycombinator.com/item?id=29845232
+
+** paste?
+   We just saw a use of =paste=. But this command can do all sorts of
+   crazy stuff joining lines.
+
+   #+begin_src bash
+     paste - - -d, < file   # joins every 2 lines with comma
+     paste - - - -d, < file   # joins every 3 lines with comma
+     paste -s -d",\n" file  #joins 1 and 2 lines with comma, 2 and 3 with \n
+   #+end_src
+
+** Scripts as filters
+   Strive to create scripts that can be used as filters. Perl had
+   =while(<>) { ... }= that would open a file line by line, or get
+   input from stdin depending on the actual arguments to the file.
+
+   In shellscripting, we can simulate (part of) it using
+   #+begin_src bash
+     while IFS= read -r line
+     do
+       echo "$line"
+     done < "${1:-/dev/stdin}"
+   #+end_src
+
+   Look [[https://stackoverflow.com/questions/6980090/how-to-read-from-a-file-or-standard-input-in-bash][here]] for more detailed explanations and variants.
+
+   Another way to create filters is to use `"${@:-cat}"`.
+
+   #+begin_src bash
+     o2e     () { 1>&2 "${@:-cat}"; } # out to err
+     e2o     () { 2>&1 "${@:-cat}"; } # err to out
+   #+end_src
+
+** Read or print to stdin inside a pipe
+    You can use /dev/tty to explicitly specify that some input or
+    output has to come from tty (being screen or keyboard).
+
+    This is useful for code that might be called inside a pipeline,
+    but you never want the contents of the pipe to be the ones that
+    are =read= or =echoed=.
+
+    Here's a snippet that defines a function fzf (if fzf is not
+    previously defined), that will naively replace fzf.
+
+   #+begin_src bash
+     # fzf is either fzf or a naive version of it
+     # the input is a sed line number, so it can be
+     # single number: 42
+     # range: 1,10
+     # separate lines: 10p;50p
+     mute command -v fzf ||
+       fzf() {
+         local in=$(cat)
+         for p in "${@}"; do
+           [ "$p" = "-0" ] && [ "$(echo "$in" | wc -l)" -eq 1 ] && [ ""  = "$in" ] && return 1
+           [ "$p" = "-1" ] && [ "$(echo "$in" | wc -l)" -eq 1 ] && [ "" != "$in" ] && echo "$in" && return
+         done
+         # https://superuser.com/questions/1748550/read-from-stdin-while-piping-to-next-command
+         cat -n <(echo "$in") >/dev/tty
+         read -n num </dev/tty
+         echo "$in" | sed -n "${num}p"
+       }
+   #+end_src
+
+   Well... after implementing this, I discovered `select`, which allows for these kinds of flows:
+
+   #+begin_src bash
+     mute command -v fzf ||
+     fzf() {
+       local in=$(cat)
+       for p in "${@}"; do
+         [ "$p" = "-0" ] && [ "$(echo "$in" | wc -l)" -eq 1 ] && [ ""  = "$in" ] && return 1
+         [ "$p" = "-1" ] && [ "$(echo "$in" | wc -l)" -eq 1 ] && [ "" != "$in" ] && echo "$in" && return
+       done
+       select opt in $(echo "$in"); do
+         [ -n "$opt" ] && break
+       done >/dev/tty </dev/tty
+       echo $opt
+     }
+   #+end_src
+
+** change loops for "mapping/reducing" functions
+*** find
+    Many times we want to run the same operation or test to lots of
+    files. Instead of looping for each file, think if =find -exec=
+    would solve it. Also, find supports multiple directories.
+
+    #+begin_src bash
+      dirs=("/usr/local/bin" "/usr/bin")
+      for d in "${dirs[@]}"; do
+        for f in $(find "$d"); do
+          echo "check if owner of $f is johndoe and group is johndoe"
+          [ `stat -c %U:%G $f` == "johndoe:johndoe" ] || die "error"
+        done
+      done
+    #+end_src
+
+    Compare it to:
+
+    #+begin_src bash
+      [ $(find "$dirs[@]" -exec stat -c '%U:%G' {} \; | grep -vc "johndoe:johndoe") == "0" ] || die "error"
+    #+end_src
+
+    Other examples might be:
+    #+begin_src bash
+      # count all lines of all docx in this dir
+      find . -type f -name "*docx" -exec pandoc "{}" -t plain \; | wc -l
+
+      #All your files have the same owner and group permissions
+      [ $(find "$files[@]" -exec stat -c '%a' {} \; | grep -Evc "^(.)\1") == "0" ]
+    #+end_src
+*** grep -Fvf
+    Three magical flags that go well together.
+
+    - =-F= Interpret the "pattern" as a Fixed string, not a pattern/regex
+    - =-v= Negate the output. Print non matching lines.
+    - =-f= The patterns to match are taken from a file.
+
+    The cool thing about combining =-f= and =-v= is that the negative
+    matches mean "lines that are not ANY of the ones in the pattern
+    file". So you can do list diffing. like =sort + diff= but more
+    flexible.
+
+    Here's a practical case of finding version numbers that we have a
+    git tag for, that do not have a title in the readme.
+
+    #+begin_src bash
+      f="readme.md"
+      ! grep -Fvf <(grep -P "^# \d\.\d\.\d\.\d$" "$f" | sed -e 's/^# //') \
+                  <(git tag | grep -P "^\d\.\d\.\d\.\d$")
+    #+end_src
+*** grep -Pzo
+    Three flags that also combine pretty nicely.
+
+    With those, we can match multiple lines using plain old grep.
+
+    This is how I get only the table structure of a postgres database.
+
+    #+begin_src bash
+      pg_dump -s | grep -Pzo "CREATE TABLE [^;]*;\n"
+    #+end_src
+
+    More info on this [[https://stackoverflow.com/questions/3717772/regex-grep-for-multi-line-search-needed/7167115#7167115][stackoverflow thread]].
+
+
+    Use of this pattern will use =\0='s instead of =\n=, which is good
+    for the grepping, but maybe it's not good for your output. You can
+    convert back =\0='s to =\n= with [[https://unix.stackexchange.com/questions/121916/convert-newlines-to-null-delimited-when-using-tail][tr.]]
+
+    #+begin_src bash
+      pg_dump -s | grep -Pzo "CREATE TABLE public.($tables) [^;]*;\n" | tr '\0' '\n' | ...
+    #+end_src
+
+
+    Alternatively, depending on your requirements, you can leverage
+    =awk=, with =awk '/CREATE TABLE/,/;/'=, that won't suffer from the
+    \0 problem. But then you need to explain the awk model to your
+    coworker.
+
+*** grep -Ec
+    Say you want to find lines that match 2 words, not just 1. in whatever order.
+
+    #+begin_src bash
+      echo "foo bar" | grep foo | grep bar # That works, but it only works for very fixed inputs.
+
+      echo "foo bar" | grep -E 'foo.*bar'  # That doesn't , because order matters.
+
+      echo "foo baz" | grep -E '(foo|bar)' | grep -E '(foo|bar)' # That is not going to work either, because if only one word matches, it will match twice.
+    #+end_src
+
+    Here's how we can match multiple things from a list.
+    =echo "foo bar" | tr ' ' '\n' |grep -Ec "(foo|bar)"=
+
+    #+begin_src bash
+
+      match_two () {
+        while read line; do
+          if [ "$(tr ' ' '\n' <<<"$line" | rg -Uc "^($search)$")" = 2 ]; then
+            echo "$line"
+          fi
+        done
+      }
+
+      cat file_with_two_words_per_line.txt | match_two "foo|bar|baz"
+    #+end_src
+
+    With this, you can find out how many matches happened in that
+    line. The example above filters lines which have 2 words from the
+    'foo|bar|baz' regex.
+*** Set operations
+There are lots of other "set level" operations you can perform on
+files/streams using basic unix tools.
+
+[[https://catonmat.net/ftp/setops.txt][This cheatsheet]] contains lots of them, which you should go read one by
+one, because bash, appart from being useful as it is, also has an
+Iversonian [[https://www.jsoftware.com/papers/tot.htm#1.2][suggestivity]] that gets more useful with time.
+
+** jq
+   Jq is more powerful than you probably think. It's not just
+   to fetch a value deep into a json dictionary.
+
+   You can fetch and transform values, and interpolate values inside
+   a string template:
+
+   #+begin_src bash
+     echo '{"a":1,"b":2}' | jq '. | "a is \(.a), and b is \(.b)."'
+   #+end_src
+
+  Or use this in a map:
+   #+begin_src bash
+     echo '[{"a":1,"b":2},{"a":3,"b":4}]' | jq -r '. |map("a is \(.a), and b is \(.b).")[]'
+   #+end_src
+
+   Maybe a little more spicy:
+
+   #+begin_src bash
+   echo '[{"host":"host1.com","user":"bob"},{"host":"host2.com","user":"alice"}]' |
+     jq  'map("scp \(.user)@\(.host):/tmp/remote-file /tmp/local-file")[]' -r |
+     xargs -d"\n" -n1 sh -c
+   #+end_src
+
+   And, make sure to read about jq functions. for example, reading nested json
+   #+begin_src bash
+     echo '{"nested":"{\"a\":2}"}' | jq '.nested | fromjson | .a '
+   #+end_src
+
+   You can also edit values in place
+   #+begin_src bash
+     echo '{"date":1643192480}' | jq '.date|=todateiso8601' #  {"date": "2022-01-26T10:22:48Z"}
+   #+end_src
+
+   And we can generalize it into a filter that updates many date fields
+   #+begin_src bash
+     join_by() { local IFS="$1"; shift; echo "$*"; }
+     # usage: echo '[{"foo":1234567890,"bar":1234567891}]' | jq_pretty_dates '.[].foo' '.[].bar'
+     # => [{"foo":"2009-02-13T23:31:30Z","bar":"2009-02-13T23:31:31Z"}]
+     jq_pretty_dates() {
+       # From the default ($@) append every element (/%/) with
+       # |=todateiso8601). That, joined by |. And that becomes the "filter" to jq.
+       jq "$(join_by "|" "${@/%/|=todateiso8601}")"
+     }
+   #+end_src
+
+   There are quite a few interesting commands in this [[https://medium.com/circuitpeople/aws-cli-with-jq-and-bash-9d54e2eabaf1'][AWS+JQ post]].
+
+   Some other cool tips from [[https://news.ycombinator.com/item?id=31141415][This HN thread]]:
+
+   #+begin_src bash
+     echo "FFFF\nDDDD" | jq -R    # reads raw text as strings. 1 line -> 1 string
+     echo "FFFF\nDDDD" | jq -R 'capture("(?<item>.*)")' # Capture groups as json elements
+   #+end_src
+
+   You can get pretty advanced with jq, and some say it's a decent
+   substitute for =sed= as a line oriented editor.
+
+   Some more advanced tutorials [[https://programminghistorian.org/en/lessons/json-and-jq][here]] and [[https://remysharp.com/drafts/jq-recipes][here]].
+
+** use jq . <<<"$var"
+   Newlines aren't allowed in json strings, and you might get a jq
+   error like:
+
+   "parse error: Invalid string: control characters from U+0000 through U+001F must be escaped at line 148, column 99"
+
+   Sometimes, strings inside json might have encoded newlines like =\n=. If you would use
+
+   =echo $var | jq .= , bash would interpolate the \n inside the json
+   string and when it gets to jq, it's an invalid json.
+
+   If instead you use =echo -E=, or =<<<"$var"=, things go smoothly.
+
+   =jq . <<<"$var"=
+
+** pass flags as a splatted array
+   There's quite a bit to chew on this example. First of all, the core
+   pattern is to build up your commandline options with an array, and
+   splat it in the final command line. For complex commands like
+   =docker= where you easily have 10+ flags it's a visual aid, and
+   also opens up the opportunities for reusing or abstracting sets of
+   options to logical blocks.
+
+   Once it's an array, we can add elements conditionally to that array
+   depending on the current run, and build the line that we'll be
+   running in the end.
+
+   #+begin_src bash
+     # Allows Ctrl-C'ing on interactive shells
+     INTERACTIVE=
+     if [[ -t 1 ]]; then INTERACTIVE="-it"; fi
+
+     local flags=(
+       # We mount it as read-only, so we make sure we are not writing anything
+       # in there, and that everything is explicitly defined
+       "-v $LOCAL_PATH/build-dir:/build-dir:ro,delegated"
+       "-v $OUTPUT_DIR:/output:rw,consistent"
+       "-v $tmp_dir:/tmp/work:rw,delegated"
+     )
+     if [[ -n $LOCAL_PATH ]]; then
+       flags+=("-v $(realpath $LOCAL_PATH)/overrides/my-other-file:/build-dir/build.json:ro")
+       flags+=("-e LOCAL_PATH=/tmp/local")
+     fi
+
+     local v_id=$(docker volume create)
+     flags+=("-v $v_id:/tmp/build")
+     on_exit "docker volume rm $v_id"
+
+     docker run --rm $INTERACTIVE ${flags[*]} $image touch /tmp/build/foo.txt
+
+     docker run --rm $INTERACTIVE ${flags[*]} fpm:latest fpm-build /tmp/build/foo.txt
+     on_exit "chown_cache $tmp_dir"
+   #+end_src
+
+   In this example we see another cool trick. Mounting a volume in 2
+   differrent containers, so not for the purpose of sharing a local
+   file/dir with the host but to share it between themselves. In that
+   case, the 2 containers don't even coexist temporarily, but use the
+   volume as a conveyor belt, passing it from container to container,
+   and each one applies "its thing".
+
+   After all the mess, someone has to cleanup everything, but we know
+   how to do it with =on_exit= trick.
+
+** inherit_errexit
+   bash 4.4+ , you can =shopt -s inherit_errexit=, and subshells will
+   inherit the errexit flag value. meaning that if you =set -Ee=,
+   anything that runs inside a subshell will throw an error at the
+   moment any command exits with =!=0=.
+** GNU Parallel
+   I can't recommend [[https://www.gnu.org/software/parallel/][parallel]] enough. The same as xargs, but in a
+   much more flexible way, parallel lets you run various jobs at a
+   time. If you have this tool into account, it doesn't just speed up
+   your runtimes, but it will force you write cleaner code. Parallel
+   execution will test your scripts so if they are not using
+   randomized tmp working directories, things will clash, etc...
+
+   Parallel in itself is such a hackerfriendly tool it deserves to be
+   deeply learned. You can use it just locally to run a process per
+   core, you can send jobs to several machines connected via a simple
+   ssh, you can bind tmux or sqlite to it, or you can write a trivial
+   job queuing system.
+
+   Man pages and official examples are a goldmine.
+
+** HEREDOCS
+   - Basic usage of heredocs:
+   #+begin_src bash
+     echo <<EOF
+$interpolated
+\$non_interpolated
+EOF
+   #+end_src
+
+   - A dash after =<<= replaces trailing spaces in here docs
+   #+begin_src bash
+     echo <<-EOF
+     $var
+     there
+     EOF
+   #+end_src
+
+   - quoting the identifier disables interpolation of variables
+   #+begin_src bash
+     echo <<'EOF'
+     $non_interpolated
+     there
+     EOF
+   #+end_src
+
+   The [[http://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Here-Documents][bash manual]] is super concise and to the point there.
+
+   The most complex case is having a heredoc which contains some bash
+   code that is ment to run remotely, and wanting to interpolate some
+   variables in the local env, and some in the remote one. [[https://stackoverflow.com/questions/4937792/using-variables-inside-a-bash-heredoc][Escaping is
+   enough for regular]] vars, but if you want to use special (=$1, $!,
+   $?=...) vars, check this out:
+
+   #+begin_src bash
+     deploy () {
+       local deploy_dir="$1"
+       ssh server1 'bash -s' <<EOSSH
+       echo "deploying => ${deploy_dir}"
+       ls -tdr ~/my-project/artifacts/* | head -n -5 | xargs rm -rf   # remove all but latest 5 directories
+       ln -nfs "\$HOME/my-project/artifacts/${deploy_dir}/my-project-0.1.0-SNAPSHOT-standalone.jar" "\$HOME/my-project/artifacts/current.jar"
+       cat ~/my-project/artifacts/current.pid | xargs kill
+       java -jar ~/my-project/artifacts/current.jar &>/dev/null &
+       lastpid=\$(echo \$!)
+       echo \$lastpid > ~/my-project/artifacts/current.pid
+     EOSSH
+     }
+   #+end_src
+
+   Refs: https://unix.stackexchange.com/questions/60688/how-to-defer-variable-expansion
+
+** HERESTRINGS
+   It's the stripped down version of HEREDOCS. Inline a single string
+   (or output of a single command) as an input string.
+
+   It's [[https://stackoverflow.com/questions/18116343/whats-the-difference-between-here-string-and-echo-pipe][kinda similar]] to what you could do with a pipe.
+   #+begin_src bash
+     cat <<<"HELLO"
+     cat <<<$(echo "HELLO")
+     echo "ECHOPIPE" | /bin/cat
+     echo "ECHOPIPE" | /bin/cat <(seq 5)
+     echo "ECHOPIPE" | /bin/cat <(seq 5) -
+     echo "ECHOPIPE" | /bin/cat <(seq 5) <<<"HERESTRING"
+     echo "ECHOPIPE" | /bin/cat <(seq 5) - <<<"HERESTRING"
+   #+end_src
+
+** __DATA__
+   I loved the Perl [[https://perldoc.perl.org/perldata#Special-Literals][__END__ and __DATA__]], features and realized it's
+   possible to do it in shellscripts.
+
+   You can append to the current file. Here's an example of a super
+   simple bookmark "manager":
+   #+begin_src bash
+     #!/usr/bin/env sh
+
+     cmd_add() {
+         shift
+         echo "$@" >> "$0"
+     }
+
+     cmd_go() {
+         sed '0,/^__DATA__$/d' "$0" |
+         dmenu -i -l 20  |
+         rev | cut -f1 -d' ' | rev |
+         xargs xdg-open
+     }
+
+     main() {
+         cmd_${1:-go} $@
+     }
+
+     main $@
+     exit
+
+     __DATA__
+     r/emacs             https://www.reddit.com/r/emacs
+   #+end_src
+** Simple Templating
+   For trivial templating, there's no need for any external tool
+   except for just variable interpolation. This is quite obvious, but
+   I use it quite often to generate repetitive bash code itself
+
+   #+begin_src bash
+   #!/usr/bin/env bash
+   is=("obj1" "obj2")
+   js=("resource1" "resource2")
+
+   for i in "${is[@]}"; do
+     for j in "${js[@]}"; do
+       echo "insert into t (obj, resource) values ('$i', '$j');"
+     done
+   done
+   #+end_src
+
+** Secrets
+   As, [[https://smallstep.com/blog/command-line-secrets/][Smallstep article]] explains, you should be careful when passing
+   around secret data like tokens between processes.
+
+   Env vars are not really safe, and there are a few tricks you can
+   use to cover your assets.
+
+** Escape single quotes in single quoted strings
+   Escaping single quoted strings doesn't work the way you'd think.
+
+   #+begin_src bash
+     # does not work
+     a='hi \'bob\''
+   #+end_src
+
+   Use =$''= strings like:
+   #+begin_src bash
+     # works!
+     a=$'hi \'bob\''
+     echo $a
+   #+end_src
+
+   Extra explanations: [[https://stackoverflow.com/questions/1250079/how-to-escape-single-quotes-within-single-quoted-strings][StackOverflow]]
+
+** any, every, lambdas, closures, and eval
+Bash has no closures, and it's not "functional", but we're going to
+see how we can combine some tricks and get decent high-level functions
+
+Here's an implementation of =any= and =every=
+
+#+begin_src bash
+any() {
+  local pred="$1"; shift
+  for i in "$@"; do
+    if $pred $i; then
+      return 0
+    fi
+  done
+  return 1
+}
+
+every() {
+  local pred="$1"; shift
+  for i in "$@"; do
+    if ! $pred $i; then
+      return 1
+    fi
+  done
+  return 0
+}
+#+end_src
+
+The usage is by passing a callback function that will return 0 or 1.
+
+#+begin_src bash
+  usage() {
+    echo "help message"
+  }
+
+  is_help() {
+    [ "$1" = "--help" ]
+  }
+
+  any is_help "$@" && usage
+#+end_src
+
+That's already cool.
+
+Did you know that functions can start also with dashes?
+
+#+begin_src bash
+  usage() {
+    echo "help message"
+  }
+
+  --help() {
+    [ "$1" = "--help" ]
+  }
+
+  any --help "$@" && usage
+#+end_src
+
+That also works. It's kinda obfuscated a bit, but hey....
+
+We can also, with the help of =eval=, create on demand functions. They
+are global, but as we're not going to multithread, we can assume it's
+ok.
+
+#+begin_src bash
+  usage() {
+    echo "help message"
+  }
+
+  any_eq() {
+    eval "_() { [ $1 = \$1 ] ; }"
+    shift
+    any _  "$@"
+  }
+
+  any_eq "--help" "$@" && usage
+  # or,
+  any_eq --help "$@" && usage
+#+end_src
+
+And the last trick, using =command_not_found_handle=, we can get into
+a kind of rails generators for these helpers
+
+#+begin_src bash
+  command_not_found_handle() {
+    IFS=_ read -a cmd <<<"$1"
+    [ "eq" = "${cmd[0]}" ] && eval "$1() { [ \"${cmd[1]}\" = \"\$1\" ] ; }"
+    "$@"
+  }
+  any eq_--help "$@" && usage
+#+end_src
+
+All these last metaprogramming tricks are not thread safe, and even
+though it's mostly ok if you use them in isolation, maybe pipes or
+coprocs would mess up your inline functions.
+
+* Interactive
+** Save your small scripts
+   Rome wasn't built in a day, and like having a journal log, most of
+   the little scripts you create, once you have enough discipline will
+   be useful for some other cases, and your functions will be
+   reusable.
+
+   Save your scripts into files early on, instead of crunching
+   everything in the repl. learn how to use a decent editor that
+   shortens the feedback cycle as much as possible.
+** Increased Interactivity
+   Knowing your shell's shortcuts for interactive use is a must. The
+   same way you learned to touchtype and you learned your editor, you
+   should learn all the shortcuts for your shell. Here's some of them.
+
+   | key    | action                              |
+   |--------+-------------------------------------|
+   | Ctrl-r | reverse-history-search              |
+   | C-a    | beginning-of-line                   |
+   | C-e    | end-of-line                         |
+   | C-w    | delete-word-backwards               |
+   | C-k    | kill-line (from point to eol)       |
+   | C-y    | paste last killed thing             |
+   | A-y    | previous killed thing (after a c-y) |
+   | C-p    | previous-line                       |
+   | C-n    | next-line                           |
+   | A-.    | insert last agument                 |
+   | A-/    | dabbrev-expand                      |
+
+   A written form of =A-.= is =$_=. It retains the last argment and
+   puts it in $_.  =test -f "FILE" && source "$_"=.
+
+** Aliases
+   Aliases are very simple substitutions of commands for a sequence of
+   other commands.  Usual example is
+
+   #+begin_src bash
+     alias ls='ls --auto-color'
+   #+end_src
+
+   Now let's move on to the interesting stuff.
+
+** functions can generate aliases
+
+   Aliases live in a global namespace for the shell, so no matter
+   where you define them, they take effect globally, possibly
+   overwriting older aliases with the same name.
+
+   Well, it's not lexical scope (far from it), but using aliases you
+   can create a string that snapshots the value you want, and capture
+   it to run it later.
+
+   Some fun stuff:
+
+   - aliasgen. Create an alias for each directory in
+     ~/workspace/. This is superceeded by =CDPATH=, but the trick is
+     still cool.
+   #+begin_src bash
+     aliasgen() {
+       for i in ~/workspace/*(/) ; do
+           DIR=$(basename $i) ;
+            alias $DIR="cd ~/workspace/$i";
+       done
+     }
+     aliasgen
+   #+end_src
+
+   - a make a shortcut to the current directory.
+   #+begin_src bash
+     function a() { alias $1=cd\ $PWD; }
+
+     mkdir -p /tmp/fing-longer
+     cd /tmp/fing-longer
+     a fl
+     cd /
+     fl
+     echo $PWD   # /tmp/fing-longer
+   #+end_src
+   A man can dream...
+
+
+   - unhist. functions can create aliases, and functions can receive
+     functions as parameters (as a string (function name)), so we can
+     combine them to advice existing functions.
+     #+begin_src bash
+       unhist () {
+         alias $1=" $1"
+       }
+       unhist unhist
+       unhist grep
+       unhist rg
+
+       noglobber() {
+           alias $1="noglob $1"
+       }
+       noglobber http
+       noglobber curl
+       noglobber git
+
+     #+end_src
+
+     #+RESULTS:
+
+   - Problem: These commands do not compose. Combination of 2 of those
+     doesn't work, because the second acts just on the textual
+     representation that it received, not the current value of the
+     alias.
+
+   # Solution :
+   #   #+begin_src bash
+   #   alias-to() {
+   #     alias $1 | sed -e "s/.*='//" -e "s/'\$//"
+   #   }
+
+   #   aliasappend() {
+   #     local cmd
+   #     if alias $1 >/dev/null; then
+   #       cmd=$(alias-to $1)
+   #     else
+   #       cmd=$1
+   #     fi
+   #     echo $cmd
+   #   }
+
+   #   muter() {
+   #     local c
+   #     c=$(aliasappend $1)
+   #     alias $1="$c >/dev/null"
+   #   }
+
+   #   unhist() {
+   #     local c
+   #     c=$(aliasappend $1)
+   #     alias $1=" $c"
+   #   }
+
+   #   unhist ls
+   #   muter ls
+   #   ls
+   # #+end_src
+** Override (advice?) common functions
+   Overriding commands is generally a bad practice as it violates the
+   principle of least surprise, but there might be occasions (mostly
+   in your local machine) where you can integrate awesome finetunnings
+   to your toolbelt.
+
+   Here we're going to get the original docker binary file
+   location. After that we declare a function called =docker= that
+   will proxy the parameters to the original =docker= program UNLESS
+   you're calling =docker run=. In that case, we're injecting a mouted
+   volume that mounts =/root/.bash_history= of the container to a file
+   hosted in the host (duh). That's a pretty cool way of keeping a
+   history of your recent commands in your containers, no matter how
+   many times you start and kill them.
+
+   #+begin_src bash
+     DOCKER_ORIG=$(which docker)
+     docker () {
+         if [[ $1 == "run" ]]; then
+             shift
+             $DOCKER_ORIG run -v $HOME/.shared_bash_history:/root/.bash_history "$@"
+         else
+             $DOCKER_ORIG "$@"
+         fi
+     }
+   #+end_src
+
+   I'm particularly fond of this trick, as it saved me tons of
+   typing. But at a personal level, it was mindblowing that sharing
+   this around the internet caused the most disparity of opinions.
+   Also, I recently read the great book "Docker in Practice" by [[https://github.com/ianmiell][Ian
+   Miell]] and there's a snippet that is 99.9% like the one I
+   created myself. That was a very cool moment.
+
+** Faster iteration on pipes
+   When testing complex pipelines:
+
+   - Make them pure (no side effects).
+   - One command per line.
+   - End lines with the pipe character.
+   - During development, end the pipeline with =cat=.
+
+   I usually use =watch -n1 'code.sh'= in a split window so I see the
+   results of what I'm doing. The advantage of
+
+   #+begin_src bash
+     curl https://www.example.com/videos/              |
+       pup 'figure.mg > a attr{href}'                  |
+       head -1                                         |
+       xargs -I{} curl -L "https://www.example.com/{}" |
+       pup 'script'                                    |
+       grep file:                                      |
+       sed -e "s/.*\(http[^ \"']*\).*/\1/"             |
+     # xargs vlc                                       |
+       cat
+   #+end_src
+
+   Over
+   #+begin_src bash
+     curl https://www.example.com/videos/                \
+       | pup 'figure.mg > a attr{href}'                  \
+       | head -1                                         \
+       | xargs -I{} curl -L "https://www.example.com/{}" \
+       | pup 'script'                                    \
+       | grep file:                                      \
+       | sed -e "s/.*\(http[^ \"']*\).*/\1/"             \
+     # xargs vlc   # doesn't work
+   #+end_src
+
+   Is that you can comment out lines on the former one, but you can't
+   do that on the latter. The =cat= trick makes it so that you have an
+   'exit' point, and you don't have to comment that one. Also, some
+   editors will indent the first one correctly, while you'll have to
+   manually indent the second one.
+
+   Small wins that compose just fine :)
+
+** Use ${var?error msg} on templates
+   If you write something to be copypasted by your user and filled in,
+   instead of =<var>=, try =${var?You need to set var}=. it allows for the user to set
+   the variable in the environment without having to replace inline,
+   and if the user forgets any, the shell will barf.
+
+** Idempotent functions
+Being able to call the same function multiple times even if you just
+called it, without having to account for "oh, did this already happen
+or not?" but instead have a mental model of "I need this to have
+happened after this function call", and consider it done, is very
+liberating from the code perspective.
+
+Also, there are subgoals, like caching slow functions, downloads, etc.
+
+*** nop subsequent calls
+   "My favourite shell scripting function definition technique:
+   idempotent functions by redefining the function as a noop inside
+   its body:
+
+   (The `true;` body is needed by some shells, e.g. bash, and not
+   others, e.g. zsh.)  " -- [[https://news.ycombinator.com/item?id=27729397][chrismorgan]]
+
+   #+begin_src bash
+  foo() {
+      foo() { true; }
+      echo "This bit will only be executed on the first foo call"
+  }
+   #+end_src
+*** Download once
+A function might be sideffecty, as in "download files". These sort of
+cases, you want to download the file only if you haven't downloaded it
+yet.
+
+=cache= here gets a cache "id" where it'll store the results of =http=
+and next time, when called with the same param, it will reuse the saved version.
+
+This pattern applies to many kinds of functions, so with slight
+modifications you can adapt it.
+
+#+begin_src bash
+cache() {
+  local path=$CACHE_DIR/$1
+  [[ -f $path ]] && cat $path && return 0
+
+  shift
+  $@ | tee $path
+
+  return 1
+}
+
+get_repos() {
+  local url="https://api.github.com/search/repositories?q=user:$USER&access_token=$GITHUB_TOKEN&per_page=100&page=$1"
+  cache $USER-repos-$1 http $url
+}
+#+end_src
+
+*** memoize with ttl, with ttl
+What if you want to cache for some time?
+
+The tricks here:
+
+- Use a file as a sentinel for the cache.
+- Create a file, set it's modification date to now()+12hours
+- check with `-nt` (newer than) and a temporary file (to have a
+  =now()= value in "file" format).
+
+#+begin_src bash
+  hmacache="/tmp/.hmacache"
+  is_recent_cache() {
+    [ "$hmacache" -nt <(echo 1) ]
+  }
+  update_cache() {
+    touch -m -t "$(date -v+12H +"%Y%m%d%H%M.%S")" "$hmacache"
+  }
+
+  main() {
+    #...
+    if ! is_recent_cache ; then
+      if ! curl -s https://hello.ts.net > /dev/null; then
+        die "Tailscale must be connected to start Harbormaster"
+      fi
+      # other slow checks
+      update_cache
+    fi
+  }
+#+end_src
+
+* Debugging
+** adding =bash= to a script to debug
+   You can add =bash= inside any script, and it'll add a sort of
+   a breakpoint, allowing you to check the state of the env and
+   manually call functions around.
+
+   If you orgainse your code in small functions, it's easy to add
+   breakpoints by just spawning bash processes inside your script.
+
+   This works also inside docker containers (if you provide =-ti= flag
+   on run).
+
+   Let's see some usual uses of docker and how we can debug our
+   scripts there:
+
+   #+begin_src bash
+     # leaves you at a shell to fiddle if all is in place after build
+     docker run -it mycomplex-image bash
+
+     # Runs /tmp/file.sh from the host inside. That's cool to make the
+     # container less airtight. Even if the image is not originally meant
+     # to, you can even override it and 'monkeypatch' the file with the one
+     # from the host anyway.
+     docker run -it -v $PWD:/tmp/ mycomplex-image /tmp/file.sh
+
+     # So now you can really add wtv you want there.
+     echo 'bash' >>$PWD/file.sh
+
+     # run+open shell at runtime to inspect the state of the script
+     docker run -it -v $PWD:/tmp/ mycomplex-image /tmp/file.sh
+   #+end_src
+
+** DRY_RUN
+   #+begin_src bash
+     if [[-n "$DRY_RUN" ]]; then
+       curl () {
+         echo curl "$@"
+       }
+     fi
+   #+end_src
+   use =command curl= to force the command, not the alias or anything
+
+   If you have many functions to mock, and you want to overabstract (bad thing):
+
+   #+begin_src bash
+
+   mock() {
+     for m in ${MOCKS[@]//,/ }; do
+       eval "$m() { echo \"mocked $m\" "\$@"; }"
+     done
+   }
+
+   MOCKS=curl,ls script.sh
+   #+end_src
+
+
+
+** Cheap debugging flag
+
+   #+begin_src bash
+     optargs "V" option; do
+     case $option in
+       V)
+         set -xa
+       ;;
+   #+end_src
+
+** explore a pipe with tee >(some_command) |
+   the =>()= is not very easy to use. Very few places where it
+   fits. Here's a nice pipe inspector though, using =tee >(cat 1>&2)=
+   trick.
+   #+begin_src bash
+     plog() {
+       # tee >(cat 1>&2)
+       local msg=${1:-plog}
+       tee >(sed -e "s/^/[$msg] /" 1>&2)
+     }
+     alias -g 'PL'=' |plog ' #zsh only
+
+     echo "a\nb" PL foo | tr 'a-z' 'A-Z' PL bar
+     # output:
+     # [foo] a     # stderr
+     # [foo] b     # stderr
+     # A           # stdout
+     # B           # stdout
+     # [bar] A     # stderr
+     # [bar] b     # stderr
+     #+end_src
+
+
+   ref: https://stackoverflow.com/questions/17983777/shell-pipe-to-multiple-commands-in-a-file
+
+** tee+sudo
+   If you wat to store a file in a root-owned dir, in the middle of
+   your pipeline, instead of running the whole thing as root, you can
+   use =sudo tee file=:
+   #+begin_src bash
+     ls | grep m >/usr/local/garbage  # fail
+     ls | grep m | sudo tee /usr/local/garbage # success!
+   #+end_src
+** quoting
+   Bash: To get a quoted version of a given string, here's what you can do:
+   #+begin_src bash
+
+     # this is my "string" I want to 'comment "on"'
+     !:q
+   #+end_src
+
+   That gives us ='#this is my "string" I want to '\''comment
+   "on"'\'''=. Neat!
+
+   I just found this trick [[https://til.simonwillison.net/til/til/bash_escaping-a-string.md][here]]. From the associated HN thread:
+   #+begin_src bash
+     function bashquote () {
+       printf '%q' "$(cat)"
+       echo
+     }
+   #+end_src
+
+   Zsh: If you're on zsh, =a-'= quotes the current line.
+* zsh-only
+** Word spliting
+   Word splitting works differently by default in zsh than in bash.
+   #+begin_src bash
+     foo="ls -las"
+     $foo
+   #+end_src
+   This works in bash, but zsh will not split by words. To make zsh
+   expand by words, there are 2 ways: =setopt SH_WORD_SPLIT= and
+   =${=foo}=.  zsh has =unsetop= command, which allows to scope where
+   you want the expansions to happen. =unsetop SH_WORD_SPLIT=.
+
+   The problem with both solutions is that none of them are compatible
+   with bash, so you'll be cornering yourself to "this only works in
+   zsh".  A way to overcome this is to use arrays, which are expanded
+   in the same way in both shells.
+
+   Or, use the same hack as you'll see later with noglob.
+
+   Refs:
+   - https://stackoverflow.com/questions/6715388/variable-expansion-is-different-in-zsh-from-that-in-bash
+   - http://zsh.sourceforge.net/FAQ/zshfaq03.html#l18
+** globbing
+   In zsh, getting a list of files that match some characteristics is
+   doable using globbing. Bash has globbing also, but in a less sophisticated way.
+
+   The basic structure of a =glob= is =pattern(qualifiers)=. Patterns
+   can contain:
+   - strings: they do exact match
+   - wildcards:  =*=, =?=, =**/=
+   - character classes: =[0-9]=
+   - choices:  =(.pdf|.djvu)=
+
+   The qualifiers are extra constraints you put on the matches. There
+   are lots of different qualifiers. Look at =zshexpn= for the
+   complete list. The ones I use more are:
+
+   - =.= Files
+   - =/= Directories
+   - =om[numberhere]=. Nth latest modified
+
+** Global aliases:
+   Zsh has 3 kinds of aliases: normal, global, and suffix. Normal ones
+   behave the same as in bash: They expand only in the first token of
+   a line.
+
+   #+begin_src bash
+   alias foo=ls
+   foo foo # -> ls: cannot access 'foo': No such file or directory
+   #+end_src
+
+   Global aliases expand anywhere in your cli, and they can expand to
+   anything.
+
+   #+begin_src bash
+   alias  -g foo=ls
+   foo foo # -> ls: cannot access 'ls': No such file or directory
+   #+end_src
+
+   These are some aliases I have in my ~/.zshrc that help me use a
+   shell in a more fluid way.
+
+   #+begin_src bash
+     alias -g P1='| awk "{print \$1}"'
+     alias -g P2='| awk "{print \$2}"'
+     alias -g P3='| awk "{print \$3}"'
+     alias -g P4='| awk "{print \$4}"'
+     alias -g P5='| awk "{print \$5}"'
+     alias -g P6='| awk "{print \$6}"'
+     alias -g PL='| awk "{print \$NF}"'
+     alias -g PN='| awk "{print \$NF}"'
+     alias -g HL='| head -20'
+     alias -g H='| head '
+     alias -g H1='| head -1'
+     alias -g TL='| tail -20'
+     alias -g T='| tail '
+     alias -g T1='T -1'
+     #alias -g tr='-ltr'
+     alias -g X='| xclip  '
+     alias -g TB='| nc termbin.com 9999 '
+     alias -g L='| less -R '
+     alias -g LR='| less -r '
+     alias -g G='| grep '
+     alias -g GI='| grep -i '
+     alias -g GG=' 2>&1 | grep '
+     alias -g GGI=' 2>&1 | grep -i '
+     alias -g GV='| grep -v '
+     alias -g V='| grep -v '
+     alias -g TAC='| tac '
+     alias -g DU='du -B1'
+
+     alias -g E2O=' 2>&1 '
+     alias -g NE=' 2>/dev/null '
+     alias -g NO=' >/dev/null '
+
+     alias -g WC='| wc -l '
+
+     alias -g J='| noglob jq'
+     alias -g JQ='| noglob jq'
+     alias -g jq='noglob jq'
+     alias -g JL='| noglob jq -C . | less -R '
+     alias -g JQL='| noglob jq -C . | less -R '
+     alias -g XMEL='| xmlstarlet el'
+     alias -g XML='| xmlstarlet sel -t -v '
+
+     alias -g LYNX="| lynx -dump -stdin "
+     alias -g H2T="| html2text "
+     alias -g TRIM="| xargs "
+     alias -g XA='| xargs -d"\n" '
+     alias -g XE="| xargs e"
+     alias -g P="| pick "
+     alias -g PP="| percol | xargs "
+     alias -g W5="watch -n5 "
+     alias -g W1="watch -n1 "
+
+
+     alias -g CB="| col -b "
+     alias -g NC="| col -b "
+     alias -g U='| uniq '
+     alias -g XT='urxvt -e '
+     alias -g DM='| dmenu '
+     alias -g DMV='| dmenu -i -l 20 '
+
+     alias -g ...='../..'
+     alias -g ....='../../..'
+     alias -g .....='../../../..'
+
+     alias -g l10='*(om[1,10])'
+     alias -g l20='*(om[1,20])'
+     alias -g l5='*(om[1,5])'
+     alias -g l='*(om[1])'
+     alias -g '**.'='**/*(.)'
+     alias -g lpdf='*.pdf(om[1])'
+     alias -g lpng='*.png(om[1])'
+
+     alias -g u='*(om[1])'
+
+     alias lsmov='ls *.(mp4|mpg|mpeg|avi|mkv)'
+     alias lspdf='ls *.(pdf|djvu)'
+     alias lsmp3='ls *.mp3'
+     alias lspng='ls *.png'
+   #+end_src
+   Now, some sequences of words can start making sense:
+
+   - =lspdf -tr TL DM XA evince=
+   - =docker exec -u root -ti $(docker ps -q H1) bash=
+   - =docker ps DM P1 XA docker stop=
+   - =docker ps P1 XA docker stop= (P1 XA does an ad-hoc [[https://bash-my-aws.org/pipe-skimming/][pipe-skimming]])
+
+** Expansion of global aliases
+   Let's dig deeper.
+   #+begin_src zsh
+   alias -g DOCK='docker ps 2..N P P1'
+   DOCK  # works fine. Echoes the id of the chosen container
+   docker stop DOCK   # does not work , because it expands to docker stop docker ps 2..N P P1
+   docker stop $(DOCK) # works fine again
+   alias -g DOCK='$(docker ps 2..N P P1)'
+   docker stop DOCK   # yay!
+   #+end_src
+
+   So, you can bind words to expansion-time results of the aliases. It
+   feels like a very powerful thing, to have this "compile time"
+   expansions. Reminds me of CL's symbol-macrolet, or IMMEDIATE Forth
+   words.
+** Autocomplete
+   Writting smart autocompletion scripts is not easy.
+
+   zsh supports =compdef _gnu_generic= type of completion, which gets
+   you very far with 0 effort.
+
+   When autocompleting after a =-= in the commandline, if your command
+   is configured like =compdef _gnu_generic mycommand=, zsh will call
+   the script with =--help= and parse the output, trying to find
+   flags, and will use them as suggestions. It's really great.
+
+   The compromise is to write a decent "--help" for your script. Which
+   is cool because your user will love it too, and you just have to
+   write it once.
+
+   The completion is not context aware though, so you can't
+   autocomplete flags after the first non-flag argument. It seems this
+   could be improved in zsh-land, by asking for the --help like
+   =mycommand args-so-far --help=. But it doesn't work like that.
+
+
+   #+begin_src zsh
+     #!/usr/bin/env bash
+     # The script can be bash-only, while the completion work in zsh-only
+     set -Eeuo pipefail
+
+     help() {
+       echo "  -h,--help    Show help"
+       echo "  -c,--command Another thing"
+     }
+
+     if [ "$1" == "--help" ];
+       help
+     fi
+   #+end_src
+
+   Now you can play with =mycommand -<TAB>=. Amazing, wow.
+
+** Create helpers and generate global aliases automagically
+   Borrowing a bit from Perl, a bit from Forth, and a bit from
+   PicoLisp, I've come to create a few helpers that abstract words
+   into a bit higher level concepts. Unifying the option selectors is
+   one, and then, other line oriented operations like =chomp, from,
+   till=.
+
+   #+begin_src bash
+     pick() {
+       if [ -z "$DISPLAY" ]; then
+         percol || fzf || slmenu -i -l 20
+       else
+         dmenu -i -l 20
+       fi
+     }
+     alias -g P='| pick'
+
+     globalias() {
+       alias -g `echo -n $1 | tr '[a-z]' '[A-Z]'`=" | $1 "
+     }
+
+     globalias fzf
+
+     # uniquify column
+     function uc () {
+       awk -F" " "!_[\$$1]++"
+     }
+     globalias uc
+
+     function from() { perl -pe "s|.*?$1|\1|" }
+     globalias from
+
+     function till() { sed -e "s|$1.*|$1|" }
+     globalias till
+
+     function chomp () { sed -e "s|.$||" }
+     globalias chomp
+   #+end_src
+
+   Again, it's a pity those do not compose well. Just be well
+   organized, or build a more elaborate hack so you can compose
+   aliases with some sort of confidence. It'll always be a hack
+   though.
+** suffix aliases don't have to match a filename
+   zsh has another type of aliases called "suffix alias". Those alias
+   allow you to define programs to open/run file types.
+   #+begin_src shell
+   alias -s docx="libreoffice"
+   #+end_src
+
+   With this said, if you write a name of a file ending with =docx= as
+   the first token in a command line, it will use libreoffice to open
+   it.
+
+   #+begin_src shell
+     invoice1.docx
+     # will effectively call libreoffice invoice1.docx
+   #+end_src
+
+   The trick here is that the parser doesn't check that the file is
+   indeed an existing file. It can be any string.
+
+   Let's look at an example of it.
+
+   #+begin_src shell
+     alias -s git="git clone"
+   #+end_src
+
+   In this case, we can easily copy a =git@github.com:.....git= from a
+   browser, and paste it into a zsh console. Then, zsh will run that
+   "file" with the command =git clone=, effectively cloning that
+   repository.
+
+   Cool, ain't it?
+
+** noglob
+   zsh has more aggressive parameter expansion, to the level that
+   =[,],...= have special meanings, and will be interpreted and
+   expanded before calling the final commands in your shell.
+
+   There are commands that you don't want ever expanded , for example,
+   when using =curl=, it's much more likely that an open bracket will
+   be ment to be there verbatim rather than expanded.
+
+   Zsh provides a command to quote the following expansions. And it's
+   called noglob.
+   #+begin_src bash
+     noglob curl http://example.com\&a[]=1
+   #+end_src
+
+** make noglob 'transparent' to bash
+   zsh and bash are mostly compatible, but there's a few things not
+   supported in bash. =noglob= is one of them. To build a shim
+   inbetween, an easy way is to just create a =~/bin/noglob= file
+   #+begin_src bash
+     $*
+   #+end_src
+
+** glob nested expansion
+   In https://news.ycombinator.com/item?id=26175894 there's a nice
+   advanced example:
+
+   #+begin_src text
+     Variable expansion syntax, glob qualifiers, and history modifiers can
+     be combined/nested quite nicely. For example, this outputs all the
+     commands available from $PATH: `echo
+     ${~${path/%/\/*(*N:t)}}`. `${~foo}` is to enable glob expansion on the
+     result of foo. `${foo/%/bar}` substitutes the end of the result of foo
+     to "bar" (i.e. it appends it); when foo is an array, it does it for
+     each element. In `/*(*N:t)`, we're adding the slash and star to the
+     paths from `$path`, then the parentheses are glob qualifiers. `*`
+     inside means only match the executables, `N` is to activate NULL_GLOB
+     for the match so that we don't get errors for globs that didn't match
+     anything, `:t` is a history mod used for globs that returns just the
+     "tail" of the result, i.e. the basename. IIRC, bash can't even nest
+     multiple parameter expansions; you need to save each step separately.
+   #+end_src
+** Some extra shortcuts for nice things
+   - =alt-'= quotes the current line. It's like =quotemeta=. great to
+     help you fight double and triple quoting when writing scripts.
+   - =alt-#= comment/uncomment and execute. Nice way to store the current line
+     for later and reach out to it again to run it for real.
+   - =ctrl-o= kill-current-line, wait for a command, and paste.
+
+** =()
+   Zsh has =<()= and =>()= like Bash, but it also has ==()=. This
+   varant is similar to =<()= but instead of creating a temporary
+   pipe, it creates a temporary file. That is useful if we want to run
+   commands that require a file instead of a pipe (most times, because
+   it uses lseek to go through it).
+
+   Node is an example of this.
+   #+begin_src shell
+    node <(echo 'setTimeout(() => console.log("foo"), 400)')   # fails
+    node =(echo 'setTimeout(() => console.log("foo"), 400)')   # works!
+  #+end_src
+
+  Or,
+
+  #+begin_src bash
+    docker run --rm -ti -v =(echo "OHAI"):/tmp/foo ubuntu cat /tmp/foo
+  #+end_src
+
+* TODO patterns
+** just use cat/netcat/pipes with <()
+
+- input
+
+  =python logger.py executable= will run the executable and monitor it
+  for error messages. Depending on the error messages it will be doing.
+
+  In order to test it, I want to run it with my own output. So what I
+  do is =python logger.py cat=. That way I can type my stuff there,
+  and even better, I can use a stream from the shell. =myexecutable |
+  python logger.py cat= still works.
+
+*** what's the unifying theory behind all that?
+    It's still not clear to me how they relate, but the feeling is
+    that there's a common thread ruling all those commands. as if they
+    generalize over the same things, or just a couple of very
+    interrelated things.
+
+    =echo= is to =cat= what =|= is to =xargs=. and =<()= and =>()= are
+    able to make static files be dynamic streams. putting =cat= and
+    =echo= inside =<()= seem like either a noop, or a leap in what can
+    be done there. Still have to figure it out.
+
+   <(grep a file.txt) , | xargs , cat, echo
+  | you-have\it-wants | executable  | file                 | stream         |
+  | executable        | X           | <(exe)               | exe \vert      |
+  | file              | <(cat file) | X                    | cat file \vert |
+  | stream            | cat         | <(grep foo file.txt) | X              |
+
+
+- output
+
+  Most of those can be tested with and =tee=. Sometimes you would like
+  the output to be an output to a file to be extramassaged.
+
+   | you-have\it-wants | executable | file       | stream |
+   | executable        | X          | >()        |        |
+   | file              |            | X          |        |
+   | stream            |            | >(cat) | X      |
+
+   lnav <(tail -F /my/logfile-that-gets-rotated-or-truncated.log)
+   cat <(date)
+
+** redirects & streams
+   - https://catonmat.net/ftp/bash-redirections-cheat-sheet.pdf
+   - https://catonmat.net/bash-one-liners-explained-part-three
+   - https://github.com/miguelmota/bash-streams-handbook
+   - https://www2.dmst.aueb.gr/dds/sw/dgsh/
+   - https://wiki.bash-hackers.org/howto/redirection_tutorial
+** The $0 pattern
+   - https://www.reddit.com/r/oilshell/comments/f6of85/four_more_posts_in_shell_the_good_parts/
+** use git staging area to diff outputs of commands
+   - https://chrismorgan.info/blog/make-and-git-diff-test-harness/
+   - [[https://news.ycombinator.com/item?id=32896051][Content based change detection with Make]]
+   - https://news.ycombinator.com/item?id=40333481
+   - https://news.ycombinator.com/item?id=32441602
+
+** coprocs
+   - https://stackoverflow.com/questions/7942632/how-to-extrace-pg-backend-pid-from-postgresql-in-shell-script-and-pass-it-to-ano/8305578#8305578
+   - https://unix.stackexchange.com/questions/86270/how-do-you-use-the-command-coproc-in-various-shells
+   - https://mbuki-mvuki.org/posts/2021-05-30-memoize-commands-or-bash-functions-with-coprocs/
+* links
+  - https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html
+  - https://www.gnu.org/software/bash/manual/html_node/
+  - https://tldp.org/LDP/abs/html/
+  - https://mywiki.wooledge.org/BashPitfalls
+  - [[https://www.youtube.com/watch?v=sCZJblyT_XM][Gary Bernhardt. The Unix Chainsaw]]
+  - https://github.com/spencertipping/. This guy has some bash sick snippets
+  - https://news.ycombinator.com/item?id=23765123
+  - https://medium.com/@joydeepubuntu/functional-programming-in-bash-145b6db336b7
+  - https://www.youtube.com/watch?v=yD2ekOEP9sU
+  - http://catern.com/posts/pipes.html
+  - https://ebzzry.io/en/zsh-tips-1/
+  - https://github.com/ssledz/bash-fun
+  - https://news.ycombinator.com/item?id=24556022
+  - https://www.datafix.com.au/BASHing/index.html
+  - https://susam.github.io/tucl/the-unix-command-language.html
+  - https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
+  - https://www.grymoire.com/Unix/Sh.html
+  - https://github.com/dylanaraps/pure-sh-bible
+  - https://github.com/dylanaraps/pure-bash-bible
+  - https://shatterealm.netlify.app/programming/2021_01_02_shiv_lets_build_a_vcs
+  - https://news.ycombinator.com/item?id=24401085
+  - https://git.sr.ht/~sircmpwn/shit
+  - [[https://github.com/p8952/bocker][bocker]]. Docker implemented in around 100 lines of bash.
+  - https://github.com/simplenetes-io/simplenetes wow
+  - https://bakkenbaeck.github.io/a-random-walk-through-git/
+  - https://github.com/WeilerWebServices/Bash
+  - https://www.netmeister.org/blog/consistent-tools.html.
+  - https://www.arp242.net/why-zsh.html. bash vs zsh differences.
+  - https://dwheeler.com/essays/filenames-in-shell.html
+  - https://lacker.io/math/2022/02/24/godels-incompleteness-in-bash.html
+  - https://www.evalapply.org/posts/shell-aint-a-bad-place-to-fp-part-1-doug-mcilroys-pipeline/ (from [[https://clojurians.slack.com/archives/C03RZGPG3/p1645563940203839][clojurians slack]])
+  - https://github.com/adityaathalye
+  - https://www.youtube.com/watch?v=BJ0uHhBkzOQ
+  - https://www.gnu.org/software/autoconf/manual/autoconf-2.60/html_node/Portable-Shell.html
+
+* From shell to lisp and everything in between
+  - [[https://github.com/oilshell/oil][Oil Shell]].
+  - [[https://rash-lang.org/][Rash]] (Racket shell)
+  - [[https://arxiv.org/pdf/2007.09436.pdf][PaSh]]: Light-touch Data-Parallel Shell Processing.
+  - [[https://www.eigenbahn.com/2020/07/08/painless-emacs-remote-shells][Painless emacs remote shells]]. Because emacs has you covered
+  - https://news.ycombinator.com/item?id=24249646 rust
+  - https://github.com/liljencrantz/crush
+  - https://github.com/artyom-poptsov/metabash
+  - https://www.nushell.sh/
+  - [[https://github.com/borkdude/babashka][Babashka]]
+  - Bash to Perl/Python/Ruby using =``= and growing from there.
+* Credits
+- Raimon Grau <[[mailto:raimonster@gmail.com][raimonster@gmail.com]]>.
+- Some examples are result of Raimon's and Lluís Esquerda's
+  conversations or real world examples.
+- people in https://news.ycombinator.com/item?id=24402571 which I'll
+  be pulling in as time allows.
diff --git a/htmlize.el b/htmlize.el
new file mode 100644
index 0000000..bbf8008
--- /dev/null
+++ b/htmlize.el
@@ -0,0 +1,1880 @@
+;;; htmlize.el --- Convert buffer text and decorations to HTML. -*- lexical-binding: t -*-
+
+;; Copyright (C) 1997-2003,2005,2006,2009,2011,2012,2014,2017,2018,2020 Hrvoje Niksic
+
+;; Author: Hrvoje Niksic <hniksic@gmail.com>
+;; Homepage: https://github.com/hniksic/emacs-htmlize
+;; Keywords: hypermedia, extensions
+;; Version: 1.58
+;; Package-Requires: ((emacs "25.1"))
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This package converts the buffer text and the associated
+;; decorations to HTML.  Mail to <hniksic@gmail.com> to discuss
+;; features and additions.  All suggestions are more than welcome.
+
+;; To use it, just switch to the buffer you want HTML-ized and type
+;; `M-x htmlize-buffer'.  You will be switched to a new buffer that
+;; contains the resulting HTML code.  You can edit and inspect this
+;; buffer, or you can just save it with C-x C-w.  `M-x htmlize-file'
+;; will find a file, fontify it, and save the HTML version in
+;; FILE.html, without any additional intervention.  `M-x
+;; htmlize-many-files' allows you to htmlize any number of files in
+;; the same manner.  `M-x htmlize-many-files-dired' does the same for
+;; files marked in a dired buffer.
+
+;; htmlize supports three types of HTML output, selected by setting
+;; `htmlize-output-type': `css', `inline-css', and `font'.  In `css'
+;; mode, htmlize uses cascading style sheets to specify colors; it
+;; generates classes that correspond to Emacs faces and uses <span
+;; class=FACE>...</span> to color parts of text.  In this mode, the
+;; produced HTML is valid under the 4.01 strict DTD, as confirmed by
+;; the W3C validator.  `inline-css' is like `css', except the CSS is
+;; put directly in the STYLE attribute of the SPAN element, making it
+;; possible to paste the generated HTML into existing HTML documents.
+;; In `font' mode, htmlize uses <font color="...">...</font> to
+;; colorize HTML, which is not standard-compliant, but works better in
+;; older browsers.  `css' mode is the default.
+
+;; You can also use htmlize from your Emacs Lisp code.  When called
+;; non-interactively, `htmlize-buffer' and `htmlize-region' will
+;; return the resulting HTML buffer, but will not change current
+;; buffer or move the point.  htmlize will do its best to work on
+;; non-windowing Emacs sessions but the result will be limited to
+;; colors supported by the terminal.
+
+;; htmlize aims for compatibility with older Emacs versions.  Please
+;; let me know if it doesn't work on the version of GNU Emacs that you
+;; are using.  The package relies on the presence of CL extensions;
+;; please don't try to remove that dependency.  I see no practical
+;; problems with using the full power of the CL extensions, except
+;; that one might learn to like them too much.
+
+;; The latest version is available at:
+;;
+;;        <https://github.com/hniksic/emacs-htmlize>
+;;        <https://code.orgmode.org/mirrors/emacs-htmlize>
+;;
+
+;; Thanks go to the many people who have sent reports and contributed
+;; comments, suggestions, and fixes.  They include Ron Gut, Bob
+;; Weiner, Toni Drabik, Peter Breton, Ville Skytta, Thomas Vogels,
+;; Juri Linkov, Maciek Pasternacki, and many others.
+
+;; User quotes: "You sir, are a sick, sick, _sick_ person. :)"
+;;                  -- Bill Perry, author of Emacs/W3
+
+
+;;; Code:
+
+(require 'cl-lib)
+(eval-when-compile
+  (defvar font-lock-auto-fontify)
+  (defvar font-lock-support-mode)
+  (defvar global-font-lock-mode))
+
+(defconst htmlize-version "1.57")
+
+(defgroup htmlize nil
+  "Convert buffer text and faces to HTML."
+  :group 'hypermedia)
+
+(defcustom htmlize-head-tags ""
+  "Additional tags to insert within HEAD of the generated document."
+  :type 'string
+  :group 'htmlize)
+
+(defcustom htmlize-output-type 'css
+  "Output type of generated HTML, one of `css', `inline-css', or `font'.
+When set to `css' (the default), htmlize will generate a style sheet
+with description of faces, and use it in the HTML document, specifying
+the faces in the actual text with <span class=\"FACE\">.
+
+When set to `inline-css', the style will be generated as above, but
+placed directly in the STYLE attribute of the span ELEMENT: <span
+style=\"STYLE\">.  This makes it easier to paste the resulting HTML to
+other documents.
+
+When set to `font', the properties will be set using layout tags
+<font>, <b>, <i>, <u>, and <strike>.
+
+`css' output is normally preferred, but `font' is still useful for
+supporting old, pre-CSS browsers, and both `inline-css' and `font' for
+easier embedding of colorized text in foreign HTML documents (no style
+sheet to carry around)."
+  :type '(choice (const css) (const inline-css) (const font))
+  :group 'htmlize)
+
+(defcustom htmlize-use-images t
+  "Whether htmlize generates `img' for images attached to buffer contents."
+  :type 'boolean
+  :group 'htmlize)
+
+(defcustom htmlize-force-inline-images nil
+  "Non-nil means generate all images inline using data URLs.
+Normally htmlize converts image descriptors with :file properties to
+relative URIs, and those with :data properties to data URIs.  With this
+flag set, the images specified as a file name are loaded into memory and
+embedded in the HTML as data URIs."
+  :type 'boolean
+  :group 'htmlize)
+
+(defcustom htmlize-max-alt-text 100
+  "Maximum size of text to use as ALT text in images.
+
+Normally when htmlize encounters text covered by the `display' property
+that specifies an image, it generates an `alt' attribute containing the
+original text.  If the text is larger than `htmlize-max-alt-text' characters,
+this will not be done."
+  :type 'integer
+  :group 'htmlize)
+
+(defcustom htmlize-transform-image 'htmlize-default-transform-image
+  "Function called to modify the image descriptor.
+
+The function is called with the image descriptor found in the buffer and
+the text the image is supposed to replace.  It should return a (possibly
+different) image descriptor property list or a replacement string to use
+instead of of the original buffer text.
+
+Returning nil is the same as returning the original text."
+  :type 'boolean
+  :group 'htmlize)
+
+(defcustom htmlize-generate-hyperlinks t
+  "Non-nil means auto-generate the links from URLs and mail addresses in buffer.
+
+This is on by default; set it to nil if you don't want htmlize to
+autogenerate such links.  Note that this option only turns off automatic
+search for contents that looks like URLs and converting them to links.
+It has no effect on whether htmlize respects the `htmlize-link' property."
+  :type 'boolean
+  :group 'htmlize)
+
+(defcustom htmlize-hyperlink-style "
+      a {
+        color: inherit;
+        background-color: inherit;
+        font: inherit;
+        text-decoration: inherit;
+      }
+      a:hover {
+        text-decoration: underline;
+      }
+"
+  "The CSS style used for hyperlinks when in CSS mode."
+  :type 'string
+  :group 'htmlize)
+
+(defcustom htmlize-replace-form-feeds t
+  "Non-nil means replace form feeds in source code with HTML separators.
+Form feeds are the ^L characters at line beginnings that are sometimes
+used to separate sections of source code.  If this variable is set to
+`t', form feed characters are replaced with the <hr> separator.  If this
+is a string, it specifies the replacement to use.  Note that <pre> is
+temporarily closed before the separator is inserted, so the default
+replacement is effectively \"</pre><hr /><pre>\".  If you specify
+another replacement, don't forget to close and reopen the <pre> if you
+want the output to remain valid HTML.
+
+If you need more elaborate processing, set this to nil and use
+htmlize-after-hook."
+  :type 'boolean
+  :group 'htmlize)
+
+(defcustom htmlize-html-charset nil
+  "The charset declared by the resulting HTML documents.
+When non-nil, causes htmlize to insert the following in the HEAD section
+of the generated HTML:
+
+  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=CHARSET\">
+
+where CHARSET is the value you've set for htmlize-html-charset.  Valid
+charsets are defined by MIME and include strings like \"iso-8859-1\",
+\"iso-8859-15\", \"utf-8\", etc.
+
+If you are using non-Latin-1 charsets, you might need to set this for
+your documents to render correctly.  Also, the W3C validator requires
+submitted HTML documents to declare a charset.  So if you care about
+validation, you can use this to prevent the validator from bitching.
+
+Needless to say, if you set this, you should actually make sure that
+the buffer is in the encoding you're claiming it is in.  (This is
+normally achieved by using the correct file coding system for the
+buffer.)  If you don't understand what that means, you should probably
+leave this option in its default setting."
+  :type '(choice (const :tag "Unset" nil)
+                 string)
+  :group 'htmlize)
+
+(defcustom htmlize-convert-nonascii-to-entities t
+  "Whether non-ASCII characters should be converted to HTML entities.
+
+When this is non-nil, characters with codes in the 128-255 range will be
+considered Latin 1 and rewritten as \"&#CODE;\".  Characters with codes
+above 255 will be converted to \"&#UCS;\", where UCS denotes the Unicode
+code point of the character.  If the code point cannot be determined,
+the character will be copied unchanged, as would be the case if the
+option were nil.
+
+When the option is nil, the non-ASCII characters are copied to HTML
+without modification.  In that case, the web server and/or the browser
+must be set to understand the encoding that was used when saving the
+buffer.  (You might also want to specify it by setting
+`htmlize-html-charset'.)
+
+Note that in an HTML entity \"&#CODE;\", CODE is always a UCS code point,
+which has nothing to do with the charset the page is in.  For example,
+\"&#169;\" *always* refers to the copyright symbol, regardless of charset
+specified by the META tag or the charset sent by the HTTP server.  In
+other words, \"&#169;\" is exactly equivalent to \"&copy;\".
+
+For most people htmlize will work fine with this option left at the
+default setting; don't change it unless you know what you're doing."
+  :type 'sexp
+  :group 'htmlize)
+
+(defcustom htmlize-ignore-face-size 'absolute
+  "Whether face size should be ignored when generating HTML.
+If this is nil, face sizes are used.  If set to t, sizes are ignored
+If set to `absolute', only absolute size specifications are ignored.
+Please note that font sizes only work with CSS-based output types."
+  :type '(choice (const :tag "Don't ignore" nil)
+                 (const :tag "Ignore all" t)
+                 (const :tag "Ignore absolute" absolute))
+  :group 'htmlize)
+
+(defcustom htmlize-css-name-prefix ""
+  "The prefix used for CSS names.
+The CSS names that htmlize generates from face names are often too
+generic for CSS files; for example, `font-lock-type-face' is transformed
+to `type'.  Use this variable to add a prefix to the generated names.
+The string \"htmlize-\" is an example of a reasonable prefix."
+  :type 'string
+  :group 'htmlize)
+
+(defcustom htmlize-use-rgb-txt t
+  "Whether `rgb.txt' should be used to convert color names to RGB.
+
+This conversion means determining, for instance, that the color
+\"IndianRed\" corresponds to the (205, 92, 92) RGB triple.  `rgb.txt'
+is the X color database that maps hundreds of color names to such RGB
+triples.  When this variable is non-nil, `htmlize' uses `rgb.txt' to
+look up color names.
+
+If this variable is nil, htmlize queries Emacs for RGB components of
+colors using `color-instance-rgb-components' and `color-values'.
+This can yield incorrect results on non-true-color displays.
+
+If the `rgb.txt' file is not found (which will be the case if you're
+running Emacs on non-X11 systems), this option is ignored."
+  :type 'boolean
+  :group 'htmlize)
+
+(defvar htmlize-face-overrides nil
+  "Overrides for face definitions.
+
+Normally face definitions are taken from Emacs settings for fonts
+in the current frame.  For faces present in this plist, the
+definitions will be used instead.  Keys in the plist are symbols
+naming the face and values are the overriding definitions.  For
+example:
+
+  (setq htmlize-face-overrides
+        \\='(font-lock-warning-face \"black\"
+          font-lock-function-name-face \"red\"
+          font-lock-comment-face \"blue\"
+          default (:foreground \"dark-green\" :background \"yellow\")))
+
+This variable can be also be `let' bound when running `htmlize-buffer'.")
+
+(defcustom htmlize-untabify t
+  "Non-nil means untabify buffer contents during htmlization."
+  :type 'boolean
+  :group 'htmlize)
+
+(defcustom htmlize-html-major-mode nil
+  "The mode the newly created HTML buffer will be put in.
+Set this to nil if you prefer the default (fundamental) mode."
+  :type '(radio (const :tag "No mode (fundamental)" nil)
+                 (function-item html-mode)
+                 (function :tag "User-defined major mode"))
+  :group 'htmlize)
+
+(defcustom htmlize-pre-style nil
+  "When non-nil, `<pre>' tags will be decorated with style
+information in `font' and `inline-css' modes. This allows a
+consistent background for captures of regions."
+  :type 'boolean
+  :group 'htmlize)
+
+(defvar htmlize-before-hook nil
+  "Hook run before htmlizing a buffer.
+The hook functions are run in the source buffer (not the resulting HTML
+buffer).")
+
+(defvar htmlize-after-hook nil
+  "Hook run after htmlizing a buffer.
+Unlike `htmlize-before-hook', these functions are run in the generated
+HTML buffer.  You may use them to modify the outlook of the final HTML
+output.")
+
+(defvar htmlize-file-hook nil
+  "Hook run by `htmlize-file' after htmlizing a file, but before saving it.")
+
+(defvar htmlize-buffer-places)
+
+(defconst htmlize-image-mime-type-alist
+  '((svg . "svg+xml")
+    )
+  "Alist mapping Emacs image types to Mime media types.
+https://www.iana.org/assignments/media-types/media-types.xhtml#image")
+
+;;; Some cross-Emacs compatibility.
+
+;; We need a function that efficiently finds the next change of a
+;; property regardless of whether the change occurred because of a
+;; text property or an extent/overlay.
+(defun htmlize-next-change (pos prop &optional limit)
+  (if prop
+      (next-single-char-property-change pos prop nil limit)
+    (next-char-property-change pos limit)))
+
+(defun htmlize-overlay-faces-at (pos)
+  (delq nil (mapcar (lambda (o) (overlay-get o 'face)) (overlays-at pos))))
+
+(defun htmlize-next-face-change (pos &optional limit)
+  ;; (htmlize-next-change pos 'face limit) would skip over entire
+  ;; overlays that specify the `face' property, even when they
+  ;; contain smaller text properties that also specify `face'.
+  ;; Emacs display engine merges those faces, and so must we.
+  (or limit
+      (setq limit (point-max)))
+  (let ((next-prop (next-single-property-change pos 'face nil limit))
+        (overlay-faces (htmlize-overlay-faces-at pos)))
+    (while (progn
+             (setq pos (next-overlay-change pos))
+             (and (< pos next-prop)
+                  (equal overlay-faces (htmlize-overlay-faces-at pos)))))
+    (setq pos (min pos next-prop))
+    ;; Additionally, we include the entire region that specifies the
+    ;; `display' property.
+    (when (get-char-property pos 'display)
+      (setq pos (next-single-char-property-change pos 'display nil limit)))
+    pos))
+
+(defmacro htmlize-lexlet (&rest letforms)
+  (declare (indent 1) (debug let))
+  (if (and (boundp 'lexical-binding)
+           lexical-binding)
+      `(let ,@letforms)
+    ;; cl extensions have a macro implementing lexical let
+    `(lexical-let ,@letforms)))
+
+
+;;; Transformation of buffer text: HTML escapes, untabification, etc.
+
+(defvar htmlize-basic-character-table
+  ;; Map characters in the 0-127 range to either one-character strings
+  ;; or to numeric entities.
+  (let ((table (make-vector 128 ?\0)))
+    ;; Map characters in the 32-126 range to themselves, others to
+    ;; &#CODE entities;
+    (dotimes (i 128)
+      (setf (aref table i) (if (and (>= i 32) (<= i 126))
+                               (char-to-string i)
+                             (format "&#%d;" i))))
+    ;; Set exceptions manually.
+    (setf
+     ;; Don't escape newline, carriage return, and TAB.
+     (aref table ?\n) "\n"
+     (aref table ?\r) "\r"
+     (aref table ?\t) "\t"
+     ;; Escape &, <, and >.
+     (aref table ?&) "&amp;"
+     (aref table ?<) "&lt;"
+     (aref table ?>) "&gt;"
+     ;; Not escaping '"' buys us a measurable speedup.  It's only
+     ;; necessary to quote it for strings used in attribute values,
+     ;; which htmlize doesn't typically do.
+     ;(aref table ?\") "&quot;"
+     )
+    table))
+
+;; A cache of HTML representation of non-ASCII characters.  Depending
+;; on the setting of `htmlize-convert-nonascii-to-entities', this maps
+;; non-ASCII characters to either "&#<code>;" or "<char>" (mapconcat's
+;; mapper must always return strings).  It's only filled as characters
+;; are encountered, so that in a buffer with e.g. French text, it will
+;; only ever contain French accented characters as keys.  It's cleared
+;; on each entry to htmlize-buffer-1 to allow modifications of
+;; `htmlize-convert-nonascii-to-entities' to take effect.
+(defvar htmlize-extended-character-cache (make-hash-table :test 'eq))
+
+(defun htmlize-protect-string (string)
+  "HTML-protect string, escaping HTML metacharacters and I18N chars."
+  ;; Only protecting strings that actually contain unsafe or non-ASCII
+  ;; chars removes a lot of unnecessary funcalls and consing.
+  (if (not (string-match "[^\r\n\t -%'-;=?-~]" string))
+      string
+    (mapconcat (lambda (char)
+                 (cond
+                  ((< char 128)
+                   ;; ASCII: use htmlize-basic-character-table.
+                   (aref htmlize-basic-character-table char))
+                  ((gethash char htmlize-extended-character-cache)
+                   ;; We've already seen this char; return the cached
+                   ;; string.
+                   )
+                  ((not htmlize-convert-nonascii-to-entities)
+                   ;; If conversion to entities is not desired, always
+                   ;; copy the char literally.
+                   (setf (gethash char htmlize-extended-character-cache)
+                         (char-to-string char)))
+                  ((< char 256)
+                   ;; Latin 1: no need to call encode-char.
+                   (setf (gethash char htmlize-extended-character-cache)
+                         (format "&#%d;" char)))
+                  ((encode-char char 'ucs)
+                   ;; Must check if encode-char works for CHAR;
+                   ;; it fails for Arabic and possibly elsewhere.
+                   (setf (gethash char htmlize-extended-character-cache)
+                         (format "&#%d;" (encode-char char 'ucs))))
+                  (t
+                   ;; encode-char doesn't work for this char.  Copy it
+                   ;; unchanged and hope for the best.
+                   (setf (gethash char htmlize-extended-character-cache)
+                         (char-to-string char)))))
+               string "")))
+
+(defun htmlize-attr-escape (string)
+  ;; Like htmlize-protect-string, but also escapes double-quoted
+  ;; strings to make it usable in attribute values.
+  (setq string (htmlize-protect-string string))
+  (if (not (string-match "\"" string))
+      string
+    (mapconcat (lambda (char)
+                 (if (eql char ?\")
+                     "&quot;"
+                   (char-to-string char)))
+               string "")))
+
+(defsubst htmlize-concat (list)
+  (if (and (consp list) (null (cdr list)))
+      ;; Don't create a new string in the common case where the list only
+      ;; consists of one element.
+      (car list)
+    (apply #'concat list)))
+
+(defun htmlize-format-link (linkprops text)
+  (let ((uri (if (stringp linkprops)
+                 linkprops
+               (plist-get linkprops :uri)))
+        (escaped-text (htmlize-protect-string text)))
+    (if uri
+        (format "<a href=\"%s\">%s</a>" (htmlize-attr-escape uri) escaped-text)
+      escaped-text)))
+
+(defun htmlize-escape-or-link (string)
+  ;; Escape STRING and/or add hyperlinks.  STRING comes from a
+  ;; `display' property.
+  (let ((pos 0) (end (length string)) outlist)
+    (while (< pos end)
+      (let* ((link (get-char-property pos 'htmlize-link string))
+             (next-link-change (next-single-property-change
+                                pos 'htmlize-link string end))
+             (chunk (substring string pos next-link-change)))
+        (push
+         (cond (link
+                (htmlize-format-link link chunk))
+               ((get-char-property 0 'htmlize-literal chunk)
+                chunk)
+               (t
+                (htmlize-protect-string chunk)))
+         outlist)
+        (setq pos next-link-change)))
+    (htmlize-concat (nreverse outlist))))
+
+(defun htmlize-display-prop-to-html (display text)
+  (let (desc)
+    (cond ((stringp display)
+           ;; Emacs ignores recursive display properties.
+           (htmlize-escape-or-link display))
+          ((not (eq (car-safe display) 'image))
+           (htmlize-protect-string text))
+          ((null (setq desc (funcall htmlize-transform-image
+                                     (cdr display) text)))
+           (htmlize-escape-or-link text))
+          ((stringp desc)
+           (htmlize-escape-or-link desc))
+          (t
+           (htmlize-generate-image desc text)))))
+
+(defun htmlize-string-to-html (string)
+  ;; Convert the string to HTML, including images attached as
+  ;; `display' property and links as `htmlize-link' property.  In a
+  ;; string without images or links, this is equivalent to
+  ;; `htmlize-protect-string'.
+  (let ((pos 0) (end (length string)) outlist)
+    (while (< pos end)
+      (let* ((display (get-char-property pos 'display string))
+             (next-display-change (next-single-property-change
+                                   pos 'display string end))
+             (chunk (substring string pos next-display-change)))
+        (push
+         (if display
+             (htmlize-display-prop-to-html display chunk)
+           (htmlize-escape-or-link chunk))
+         outlist)
+        (setq pos next-display-change)))
+    (htmlize-concat (nreverse outlist))))
+
+(defun htmlize-default-transform-image (imgprops _text)
+  "Default transformation of image descriptor to something usable in HTML.
+
+If `htmlize-use-images' is nil, the function always returns nil, meaning
+use original text.  Otherwise, it tries to find the image for images that
+specify a file name.  If `htmlize-force-inline-images' is non-nil, it also
+converts the :file attribute to :data and returns the modified property
+list."
+  (when htmlize-use-images
+    (when (plist-get imgprops :file)
+      (let ((location (plist-get (cdr (find-image (list imgprops))) :file)))
+        (when location
+          (setq imgprops (plist-put (cl-copy-list imgprops) :file location)))))
+    (if htmlize-force-inline-images
+        (let ((location (plist-get imgprops :file))
+              data)
+          (when location
+            (with-temp-buffer
+              (condition-case nil
+                  (progn
+                    (insert-file-contents-literally location)
+                    (setq data (buffer-string)))
+                (error nil))))
+          ;; if successful, return the new plist, otherwise return
+          ;; nil, which will use the original text
+          (and data
+               (plist-put (plist-put imgprops :file nil)
+                          :data data)))
+      imgprops)))
+
+(defun htmlize-alt-text (_imgprops origtext)
+  (and (/= (length origtext) 0)
+       (<= (length origtext) htmlize-max-alt-text)
+       (not (string-match "[\0-\x1f]" origtext))
+       origtext))
+
+(defun htmlize-generate-image (imgprops origtext)
+  (let* ((alt-text (htmlize-alt-text imgprops origtext))
+         (alt-attr (if alt-text
+                       (format " alt=\"%s\"" (htmlize-attr-escape alt-text))
+                     "")))
+    (cond ((plist-get imgprops :file)
+           ;; Try to find the image in image-load-path
+           (let* ((found-props (cdr (find-image (list imgprops))))
+                  (file (or (plist-get found-props :file)
+                            (plist-get imgprops :file))))
+             (format "<img src=\"%s\"%s />"
+                     (htmlize-attr-escape (file-relative-name file))
+                     alt-attr)))
+          ((plist-get imgprops :data)
+           (let ((image-type (plist-get imgprops :type)))
+             (format "<img src=\"data:image/%s;base64,%s\"%s />"
+                     (or (alist-get image-type htmlize-image-mime-type-alist) image-type "")
+                     (base64-encode-string (plist-get imgprops :data))
+                     alt-attr))))))
+
+(defconst htmlize-ellipsis (propertize "..." 'htmlize-ellipsis t))
+
+(defun htmlize-match-inv-spec (inv)
+  (cl-member inv buffer-invisibility-spec
+             :key (lambda (i)
+                    (if (symbolp i) i (car i)))))
+
+(defun htmlize-decode-invisibility-spec (invisible)
+  ;; Return t, nil, or `ellipsis', depending on how invisible text should
+  ;; be inserted.
+
+  (if (not (listp buffer-invisibility-spec))
+      ;; If buffer-invisibility-spec is not a list, then all
+      ;; characters with non-nil `invisible' property are visible.
+      (not invisible)
+
+    ;; Otherwise, the value of a non-nil `invisible' property can be:
+    ;; 1. a symbol -- make the text invisible if it matches
+    ;;    buffer-invisibility-spec.
+    ;; 2. a list of symbols -- make the text invisible if
+    ;;    any symbol in the list matches
+    ;;    buffer-invisibility-spec.
+    ;; If the match of buffer-invisibility-spec has a non-nil
+    ;; CDR, replace the invisible text with an ellipsis.
+    (let ((match (if (symbolp invisible)
+                     (htmlize-match-inv-spec invisible)
+                   (cl-some #'htmlize-match-inv-spec invisible))))
+      (cond ((null match) t)
+            ((cdr-safe (car match)) 'ellipsis)
+            (t nil)))))
+
+(defun htmlize-add-before-after-strings (beg end text)
+  ;; Find overlays specifying before-string and after-string in [beg,
+  ;; pos).  If any are found, splice them into TEXT and return the new
+  ;; text.
+  (let (additions)
+    (dolist (overlay (overlays-in beg end))
+      (let ((before (overlay-get overlay 'before-string))
+            (after (overlay-get overlay 'after-string)))
+        (when after
+          (push (cons (- (overlay-end overlay) beg)
+                      after)
+                additions))
+        (when before
+          (push (cons (- (overlay-start overlay) beg)
+                      before)
+                additions))))
+    (if additions
+        (let ((textlist nil)
+              (strpos 0))
+          (dolist (add (cl-stable-sort additions #'< :key #'car))
+            (let ((addpos (car add))
+                  (addtext (cdr add)))
+              (push (substring text strpos addpos) textlist)
+              (push addtext textlist)
+              (setq strpos addpos)))
+          (push (substring text strpos) textlist)
+          (apply #'concat (nreverse textlist)))
+      text)))
+
+(defun htmlize-copy-prop (prop beg end string)
+  ;; Copy the specified property from the specified region of the
+  ;; buffer to the target string.  We cannot rely on Emacs to copy the
+  ;; property because we want to handle properties coming from both
+  ;; text properties and overlays.
+  (let ((pos beg))
+    (while (< pos end)
+      (let ((value (get-char-property pos prop))
+            (next-change (htmlize-next-change pos prop end)))
+        (when value
+          (put-text-property (- pos beg) (- next-change beg)
+                             prop value string))
+        (setq pos next-change)))))
+
+(defun htmlize-get-text-with-display (beg end)
+  ;; Like buffer-substring-no-properties, except it copies the
+  ;; `display' property from the buffer, if found.
+  (let ((text (buffer-substring-no-properties beg end)))
+    (htmlize-copy-prop 'display beg end text)
+    (htmlize-copy-prop 'htmlize-link beg end text)
+    (setq text (htmlize-add-before-after-strings beg end text))
+    text))
+
+(defun htmlize-buffer-substring-no-invisible (beg end)
+  ;; Like buffer-substring-no-properties, but don't copy invisible
+  ;; parts of the region.  Where buffer-substring-no-properties
+  ;; mandates an ellipsis to be shown, htmlize-ellipsis is inserted.
+  (let ((pos beg)
+        visible-list invisible show last-show next-change)
+    ;; Iterate over the changes in the `invisible' property and filter
+    ;; out the portions where it's non-nil, i.e. where the text is
+    ;; invisible.
+    (while (< pos end)
+      (setq invisible (get-char-property pos 'invisible)
+            next-change (htmlize-next-change pos 'invisible end)
+            show (htmlize-decode-invisibility-spec invisible))
+      (cond ((eq show t)
+             (push (htmlize-get-text-with-display pos next-change)
+                   visible-list))
+            ((and (eq show 'ellipsis)
+                  (not (eq last-show 'ellipsis))
+                  ;; Conflate successive ellipses.
+                  (push htmlize-ellipsis visible-list))))
+      (setq pos next-change last-show show))
+    (htmlize-concat (nreverse visible-list))))
+
+(defun htmlize-trim-ellipsis (text)
+  ;; Remove htmlize-ellipses ("...") from the beginning of TEXT if it
+  ;; starts with it.  It checks for the special property of the
+  ;; ellipsis so it doesn't work on ordinary text that begins with
+  ;; "...".
+  (if (get-text-property 0 'htmlize-ellipsis text)
+      (substring text (length htmlize-ellipsis))
+    text))
+
+(defconst htmlize-tab-spaces
+  ;; A table of strings with spaces.  (aref htmlize-tab-spaces 5) is
+  ;; like (make-string 5 ?\ ), except it doesn't cons.
+  (let ((v (make-vector 32 nil)))
+    (dotimes (i (length v))
+      (setf (aref v i) (make-string i ?\ )))
+    v))
+
+(defun htmlize-untabify-string (text start-column)
+  "Untabify TEXT, assuming it starts at START-COLUMN."
+  (let ((column start-column)
+        (last-match 0)
+        (chunk-start 0)
+        chunks match-pos tab-size)
+    (while (string-match "[\t\n]" text last-match)
+      (setq match-pos (match-beginning 0))
+      (cond ((eq (aref text match-pos) ?\t)
+             ;; Encountered a tab: create a chunk of text followed by
+             ;; the expanded tab.
+             (push (substring text chunk-start match-pos) chunks)
+             ;; Increase COLUMN by the length of the text we've
+             ;; skipped since last tab or newline.  (Encountering
+             ;; newline resets it.)
+             (cl-incf column (- match-pos last-match))
+             ;; Calculate tab size based on tab-width and COLUMN.
+             (setq tab-size (- tab-width (% column tab-width)))
+             ;; Expand the tab, carefully recreating the `display'
+             ;; property if one was on the TAB.
+             (let ((display (get-text-property match-pos 'display text))
+                   (expanded-tab (aref htmlize-tab-spaces tab-size)))
+               (when display
+                 (setq expanded-tab (copy-sequence expanded-tab))
+                 (put-text-property 0 tab-size 'display display expanded-tab))
+               (push expanded-tab chunks))
+             (cl-incf column tab-size)
+             (setq chunk-start (1+ match-pos)))
+            (t
+             ;; Reset COLUMN at beginning of line.
+             (setq column 0)))
+      (setq last-match (1+ match-pos)))
+    ;; If no chunks have been allocated, it means there have been no
+    ;; tabs to expand.  Return TEXT unmodified.
+    (if (null chunks)
+        text
+      (when (< chunk-start (length text))
+        ;; Push the remaining chunk.
+        (push (substring text chunk-start) chunks))
+      ;; Generate the output from the available chunks.
+      (htmlize-concat (nreverse chunks)))))
+
+(defun htmlize-extract-text (beg end trailing-ellipsis)
+  ;; Extract buffer text, sans the invisible parts.  Then
+  ;; untabify it and escape the HTML metacharacters.
+  (let ((text (htmlize-buffer-substring-no-invisible beg end)))
+    (when trailing-ellipsis
+      (setq text (htmlize-trim-ellipsis text)))
+    ;; If TEXT ends up empty, don't change trailing-ellipsis.
+    (when (> (length text) 0)
+      (setq trailing-ellipsis
+            (get-text-property (1- (length text))
+                               'htmlize-ellipsis text)))
+    (when htmlize-untabify
+      (setq text (htmlize-untabify-string text (current-column))))
+    (setq text (htmlize-string-to-html text))
+    (cl-values text trailing-ellipsis)))
+
+(defun htmlize-despam-address (string)
+  "Replace every occurrence of '@' in STRING with %40.
+This is used to protect mailto links without modifying their meaning."
+  ;; Suggested by Ville Skytta.
+  (while (string-match "@" string)
+    (setq string (replace-match "%40" nil t string)))
+  string)
+
+(defun htmlize-make-tmp-overlay (beg end props)
+  (let ((overlay (make-overlay beg end)))
+    (overlay-put overlay 'htmlize-tmp-overlay t)
+    (while props
+      (overlay-put overlay (pop props) (pop props)))
+    overlay))
+
+(defun htmlize-delete-tmp-overlays ()
+  (dolist (overlay (overlays-in (point-min) (point-max)))
+    (when (overlay-get overlay 'htmlize-tmp-overlay)
+      (delete-overlay overlay))))
+
+(defun htmlize-make-link-overlay (beg end uri)
+  (htmlize-make-tmp-overlay beg end `(htmlize-link (:uri ,uri))))
+
+(defun htmlize-create-auto-links ()
+  "Add `htmlize-link' property to all mailto links in the buffer."
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward
+            "<\\(\\(mailto:\\)?\\([-=+_.a-zA-Z0-9]+@[-_.a-zA-Z0-9]+\\)\\)>"
+            nil t)
+      (let* ((address (match-string 3))
+             (beg (match-beginning 0)) (end (match-end 0))
+             (uri (concat "mailto:" (htmlize-despam-address address))))
+        (htmlize-make-link-overlay beg end uri)))
+    (goto-char (point-min))
+    (while (re-search-forward "<\\(\\(URL:\\)?\\([a-zA-Z]+://[^;]+\\)\\)>"
+                              nil t)
+      (htmlize-make-link-overlay
+       (match-beginning 0) (match-end 0) (match-string 3)))))
+
+;; Tests for htmlize-create-auto-links:
+
+;; <mailto:hniksic@xemacs.org>
+;; <http://fly.srk.fer.hr>
+;; <URL:http://www.xemacs.org>
+;; <http://www.mail-archive.com/bbdb-info@xemacs.org/>
+;; <hniksic@xemacs.org>
+;; <xalan-dev-sc.10148567319.hacuhiucknfgmpfnjcpg-john=doe.com@xml.apache.org>
+
+(defun htmlize-shadow-form-feeds ()
+  (let ((s (propertize "\n<hr />" 'htmlize-literal t)))
+    (let ((disp `(display ,s)))
+      (while (re-search-forward "\n\^L" nil t)
+        (let* ((beg (match-beginning 0))
+               (end (match-end 0))
+               (form-feed-pos (1+ beg))
+               ;; don't process ^L if invisible or covered by `display'
+               (show (and (htmlize-decode-invisibility-spec
+                           (get-char-property form-feed-pos 'invisible))
+                          (not (get-char-property form-feed-pos 'display)))))
+          (when show
+            (htmlize-make-tmp-overlay beg end disp)))))))
+
+(defun htmlize-defang-local-variables ()
+  ;; Juri Linkov reports that an HTML-ized "Local variables" can lead
+  ;; visiting the HTML to fail with "Local variables list is not
+  ;; properly terminated".  He suggested changing the phrase to
+  ;; syntactically equivalent HTML that Emacs doesn't recognize.
+  (goto-char (point-min))
+  (while (search-forward "Local Variables:" nil t)
+    (replace-match "Local Variables&#58;" nil t)))
+
+
+;;; Color handling.
+
+(defvar htmlize-x-library-search-path
+  `(,data-directory
+    "/etc/X11/rgb.txt"
+    "/usr/share/X11/rgb.txt"
+    ;; the remainder of this list really belongs in a museum
+    "/usr/X11R6/lib/X11/"
+    "/usr/X11R5/lib/X11/"
+    "/usr/lib/X11R6/X11/"
+    "/usr/lib/X11R5/X11/"
+    "/usr/local/X11R6/lib/X11/"
+    "/usr/local/X11R5/lib/X11/"
+    "/usr/local/lib/X11R6/X11/"
+    "/usr/local/lib/X11R5/X11/"
+    "/usr/X11/lib/X11/"
+    "/usr/lib/X11/"
+    "/usr/local/lib/X11/"
+    "/usr/X386/lib/X11/"
+    "/usr/x386/lib/X11/"
+    "/usr/XFree86/lib/X11/"
+    "/usr/unsupported/lib/X11/"
+    "/usr/athena/lib/X11/"
+    "/usr/local/x11r5/lib/X11/"
+    "/usr/lpp/Xamples/lib/X11/"
+    "/usr/openwin/lib/X11/"
+    "/usr/openwin/share/lib/X11/"))
+
+(defun htmlize-get-color-rgb-hash (&optional rgb-file)
+  "Return a hash table mapping X color names to RGB values.
+The keys in the hash table are X11 color names, and the values are the
+#rrggbb RGB specifications, extracted from `rgb.txt'.
+
+If RGB-FILE is nil, the function will try hard to find a suitable file
+in the system directories.
+
+If no rgb.txt file is found, return nil."
+  (let ((rgb-file (or rgb-file (locate-file
+                                "rgb.txt"
+                                htmlize-x-library-search-path)))
+        (hash nil))
+    (when rgb-file
+      (with-temp-buffer
+        (insert-file-contents rgb-file)
+        (setq hash (make-hash-table :test 'equal))
+        (while (not (eobp))
+          (cond ((looking-at "^\\s-*\\([!#]\\|$\\)")
+                 ;; Skip comments and empty lines.
+                 )
+                ((looking-at
+                  "[ \t]*\\([0-9]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\(.*\\)")
+                 (setf (gethash (downcase (match-string 4)) hash)
+                       (format "#%02x%02x%02x"
+                               (string-to-number (match-string 1))
+                               (string-to-number (match-string 2))
+                               (string-to-number (match-string 3)))))
+                (t
+                 (error
+                  "Unrecognized line in %s: %s"
+                  rgb-file
+                  (buffer-substring (point) (progn (end-of-line) (point))))))
+          (forward-line 1))))
+    hash))
+
+;; Compile the RGB map when loaded.  On systems where rgb.txt is
+;; missing, the value of the variable will be nil, and rgb.txt will
+;; not be used.
+(defvar htmlize-color-rgb-hash (htmlize-get-color-rgb-hash))
+
+;;; Face handling.
+
+(defun htmlize-face-color-internal (face fg)
+  ;; Used only under GNU Emacs.  Return the color of FACE, but don't
+  ;; return "unspecified-fg" or "unspecified-bg".  If the face is
+  ;; `default' and the color is unspecified, look up the color in
+  ;; frame parameters.
+  (let* ((function (if fg #'face-foreground #'face-background))
+         (color (funcall function face nil t)))
+    (when (and (eq face 'default) (null color))
+      (setq color (cdr (assq (if fg 'foreground-color 'background-color)
+                             (frame-parameters)))))
+    (when (or (eq color 'unspecified)
+              (equal color "unspecified-fg")
+              (equal color "unspecified-bg"))
+      (setq color nil))
+    (when (and (eq face 'default)
+               (null color))
+      ;; Assuming black on white doesn't seem right, but I can't think
+      ;; of anything better to do.
+      (setq color (if fg "black" "white")))
+    color))
+
+(defun htmlize-face-foreground (face)
+  ;; Return the name of the foreground color of FACE.  If FACE does
+  ;; not specify a foreground color, return nil.
+  (htmlize-face-color-internal face t))
+
+(defun htmlize-face-background (face)
+  ;; Return the name of the background color of FACE.  If FACE does
+  ;; not specify a background color, return nil.
+  ;; GNU Emacs.
+  (htmlize-face-color-internal face nil))
+
+;; Convert COLOR to the #RRGGBB string.  If COLOR is already in that
+;; format, it's left unchanged.
+
+(defun htmlize-color-to-rgb (color)
+  (let ((rgb-string nil))
+    (cond ((null color)
+           ;; Ignore nil COLOR because it means that the face is not
+           ;; specifying any color.  Hence (htmlize-color-to-rgb nil)
+           ;; returns nil.
+           )
+          ((string-match "\\`#" color)
+           ;; The color is already in #rrggbb format.
+           (setq rgb-string color))
+          ((and htmlize-use-rgb-txt
+                htmlize-color-rgb-hash)
+           ;; Use of rgb.txt is requested, and it's available on the
+           ;; system.  Use it.
+           (setq rgb-string (gethash (downcase color) htmlize-color-rgb-hash)))
+          (t
+           ;; We're getting the RGB components from Emacs.
+           (let ((rgb (mapcar (lambda (arg)
+                                (/ arg 256))
+                              (color-values color))))
+             (when rgb
+               (setq rgb-string (apply #'format "#%02x%02x%02x" rgb))))))
+    ;; If RGB-STRING is still nil, it means the color cannot be found,
+    ;; for whatever reason.  In that case just punt and return COLOR.
+    ;; Most browsers support a decent set of color names anyway.
+    (or rgb-string color)))
+
+;; We store the face properties we care about into an
+;; `htmlize-fstruct' type.  That way we only have to analyze face
+;; properties, which can be time consuming, once per each face.  The
+;; mapping between Emacs faces and htmlize-fstructs is established by
+;; htmlize-make-face-map.  The name "fstruct" refers to variables of
+;; type `htmlize-fstruct', while the term "face" is reserved for Emacs
+;; faces.
+
+(cl-defstruct htmlize-fstruct
+  foreground                            ; foreground color, #rrggbb
+  background                            ; background color, #rrggbb
+  size                                  ; size
+  boldp                                         ; whether face is bold
+  italicp                               ; whether face is italic
+  underlinep                            ; whether face is underlined
+  overlinep                             ; whether face is overlined
+  strikep                               ; whether face is struck through
+  css-name                              ; CSS name of face
+  )
+
+(defun htmlize-face-set-from-keyword-attr (fstruct attr value)
+  ;; For ATTR and VALUE, set the equivalent value in FSTRUCT.
+  (cl-case attr
+    (:foreground
+     (setf (htmlize-fstruct-foreground fstruct) (htmlize-color-to-rgb value)))
+    (:background
+     (setf (htmlize-fstruct-background fstruct) (htmlize-color-to-rgb value)))
+    (:height
+     (setf (htmlize-fstruct-size fstruct) value))
+    (:weight
+     (when (string-match (symbol-name value) "bold")
+       (setf (htmlize-fstruct-boldp fstruct) t)))
+    (:slant
+     (setf (htmlize-fstruct-italicp fstruct) (or (eq value 'italic)
+                                                 (eq value 'oblique))))
+    (:bold
+     (setf (htmlize-fstruct-boldp fstruct) value))
+    (:italic
+     (setf (htmlize-fstruct-italicp fstruct) value))
+    (:underline
+     (setf (htmlize-fstruct-underlinep fstruct) value))
+    (:overline
+     (setf (htmlize-fstruct-overlinep fstruct) value))
+    (:strike-through
+     (setf (htmlize-fstruct-strikep fstruct) value))))
+
+(defun htmlize-face-size (face)
+  ;; The size (height) of FACE, taking inheritance into account.
+  ;; Only works in Emacs 21 and later.
+  (let* ((face-list (list face))
+         (head face-list)
+         (tail face-list))
+    (while head
+      (let ((inherit (face-attribute (car head) :inherit)))
+        (cond ((listp inherit)
+               (setq tail (last inherit)))
+              ((eq inherit 'unspecified))
+              (t
+               (setcdr tail (list inherit))
+               (setq tail (cdr tail)))))
+      (pop head))
+    (let ((size-list
+           (cl-loop
+            for f in face-list
+            for h = (and (facep f) (face-attribute f :height))
+            collect (if (eq h 'unspecified) nil h))))
+      (cl-reduce 'htmlize-merge-size (cons nil size-list)))))
+
+(defun htmlize-face-css-name (face)
+  ;; Generate the css-name property for the given face.  Emacs places
+  ;; no restrictions on the names of symbols that represent faces --
+  ;; any characters may be in the name, even control chars.  We try
+  ;; hard to beat the face name into shape, both esthetically and
+  ;; according to CSS1 specs.
+  (let ((name (downcase (symbol-name face))))
+    (when (string-match "\\`font-lock-" name)
+      ;; font-lock-FOO-face -> FOO.
+      (setq name (replace-match "" t t name)))
+    (when (string-match "-face\\'" name)
+      ;; Drop the redundant "-face" suffix.
+      (setq name (replace-match "" t t name)))
+    (while (string-match "[^-a-zA-Z0-9]" name)
+      ;; Drop the non-alphanumerics.
+      (setq name (replace-match "X" t t name)))
+    (when (string-match "\\`[-0-9]" name)
+      ;; CSS identifiers may not start with a digit.
+      (setq name (concat "X" name)))
+    ;; After these transformations, the face could come out empty.
+    (when (equal name "")
+      (setq name "face"))
+    ;; Apply the prefix.
+    (concat htmlize-css-name-prefix name)))
+
+(defun htmlize-face-to-fstruct-1 (face)
+  "Convert Emacs face FACE to fstruct, internal."
+  (let ((fstruct (make-htmlize-fstruct
+                  :foreground (htmlize-color-to-rgb
+                               (htmlize-face-foreground face))
+                  :background (htmlize-color-to-rgb
+                               (htmlize-face-background face)))))
+    ;; GNU Emacs
+    (dolist (attr '(:weight :slant :underline :overline :strike-through))
+      (let ((value (face-attribute face attr nil t)))
+        (when (and value (not (eq value 'unspecified)))
+          (htmlize-face-set-from-keyword-attr fstruct attr value))))
+    (let ((size (htmlize-face-size face)))
+      (unless (eql size 1.0)            ; ignore non-spec
+        (setf (htmlize-fstruct-size fstruct) size)))
+    (setf (htmlize-fstruct-css-name fstruct) (htmlize-face-css-name face))
+    fstruct))
+
+(defun htmlize-face-to-fstruct (face)
+  (let* ((face-list (or (and (symbolp face)
+                             (cdr (assq face face-remapping-alist)))
+                        (list face)))
+         (fstruct (htmlize-merge-faces
+                   (mapcar (lambda (face)
+                             (if (symbolp face)
+                                 (or (htmlize-get-override-fstruct face)
+                                     (htmlize-face-to-fstruct-1 face))
+                               (htmlize-attrlist-to-fstruct face)))
+                           (nreverse face-list)))))
+    (when (symbolp face)
+      (setf (htmlize-fstruct-css-name fstruct) (htmlize-face-css-name face)))
+    fstruct))
+
+(defmacro htmlize-copy-attr-if-set (attr-list dest source)
+  ;; Generate code with the following pattern:
+  ;; (progn
+  ;;   (when (htmlize-fstruct-ATTR source)
+  ;;     (setf (htmlize-fstruct-ATTR dest) (htmlize-fstruct-ATTR source)))
+  ;;   ...)
+  ;; for the given list of boolean attributes.
+  (cons 'progn
+        (cl-loop for attr in attr-list
+                 for attr-sym = (intern (format "htmlize-fstruct-%s" attr))
+                 collect `(when (,attr-sym ,source)
+                            (setf (,attr-sym ,dest) (,attr-sym ,source))))))
+
+(defun htmlize-merge-size (merged next)
+  ;; Calculate the size of the merge of MERGED and NEXT.
+  (cond ((null merged)     next)
+        ((integerp next)   next)
+        ((null next)       merged)
+        ((floatp merged)   (* merged next))
+        ((integerp merged) (round (* merged next)))))
+
+(defun htmlize-merge-two-faces (merged next)
+  (htmlize-copy-attr-if-set
+   (foreground background boldp italicp underlinep overlinep strikep)
+   merged next)
+  (setf (htmlize-fstruct-size merged)
+        (htmlize-merge-size (htmlize-fstruct-size merged)
+                            (htmlize-fstruct-size next)))
+  merged)
+
+(defun htmlize-merge-faces (fstruct-list)
+  (cond ((null fstruct-list)
+         ;; Nothing to do, return a dummy face.
+         (make-htmlize-fstruct))
+        ((null (cdr fstruct-list))
+         ;; Optimize for the common case of a single face, simply
+         ;; return it.
+         (car fstruct-list))
+        (t
+         (cl-reduce #'htmlize-merge-two-faces
+                    (cons (make-htmlize-fstruct) fstruct-list)))))
+
+;; GNU Emacs 20+ supports attribute lists in `face' properties.  For
+;; example, you can use `(:foreground "red" :weight bold)' as an
+;; overlay's "face", or you can even use a list of such lists, etc.
+;; We call those "attrlists".
+;;
+;; htmlize supports attrlist by converting them to fstructs, the same
+;; as with regular faces.
+
+(defun htmlize-attrlist-to-fstruct (attrlist &optional name)
+  ;; Like htmlize-face-to-fstruct, but accepts an ATTRLIST as input.
+  (let ((fstruct (make-htmlize-fstruct)))
+    (cond ((eq (car attrlist) 'foreground-color)
+           ;; ATTRLIST is (foreground-color . COLOR)
+           (setf (htmlize-fstruct-foreground fstruct)
+                 (htmlize-color-to-rgb (cdr attrlist))))
+          ((eq (car attrlist) 'background-color)
+           ;; ATTRLIST is (background-color . COLOR)
+           (setf (htmlize-fstruct-background fstruct)
+                 (htmlize-color-to-rgb (cdr attrlist))))
+          (t
+           ;; ATTRLIST is a plist.
+           (while attrlist
+             (let ((attr (pop attrlist))
+                   (value (pop attrlist)))
+               (when (and value (not (eq value 'unspecified)))
+                 (htmlize-face-set-from-keyword-attr fstruct attr value))))))
+    (setf (htmlize-fstruct-css-name fstruct) (or name "custom"))
+    fstruct))
+
+(defun htmlize-decode-face-prop (prop)
+  "Turn face property PROP into a list of face-like objects."
+  ;; PROP can be a symbol naming a face, a string naming such a
+  ;; symbol, a cons (foreground-color . COLOR) or (background-color
+  ;; COLOR), a property list (:attr1 val1 :attr2 val2 ...), or a list
+  ;; of any of those.
+  ;;
+  ;; (htmlize-decode-face-prop 'face) -> (face)
+  ;; (htmlize-decode-face-prop '(face1 face2)) -> (face1 face2)
+  ;; (htmlize-decode-face-prop '(:attr "val")) -> ((:attr "val"))
+  ;; (htmlize-decode-face-prop '((:attr "val") face (foreground-color "red")))
+  ;;   -> ((:attr "val") face (foreground-color "red"))
+  ;;
+  ;; Unrecognized atoms or non-face symbols/strings are silently
+  ;; stripped away.
+  (cond ((null prop)
+         nil)
+        ((symbolp prop)
+         (and (facep prop)
+              (list prop)))
+        ((stringp prop)
+         (and (facep (intern-soft prop))
+              (list prop)))
+        ((atom prop)
+         nil)
+        ((and (symbolp (car prop))
+              (eq ?: (aref (symbol-name (car prop)) 0)))
+         (list prop))
+        ((or (eq (car prop) 'foreground-color)
+             (eq (car prop) 'background-color))
+         (list prop))
+        (t
+         (apply #'nconc (mapcar #'htmlize-decode-face-prop prop)))))
+
+(defun htmlize-get-override-fstruct (face)
+  (let* ((raw-def (plist-get htmlize-face-overrides face))
+         (def (cond ((stringp raw-def) (list :foreground raw-def))
+                    ((listp raw-def) raw-def)
+                    (t
+                     (error (format (concat "face override must be an "
+                                            "attribute list or string, got %s")
+                                    raw-def))))))
+    (and def
+         (htmlize-attrlist-to-fstruct def (symbol-name face)))))
+
+(defun htmlize-make-face-map (faces)
+  ;; Return a hash table mapping Emacs faces to htmlize's fstructs.
+  ;; The keys are either face symbols or attrlists, so the test
+  ;; function must be `equal'.
+  (let ((face-map (make-hash-table :test 'equal))
+        css-names)
+    (dolist (face faces)
+      (unless (gethash face face-map)
+        ;; Haven't seen FACE yet; convert it to an fstruct and cache
+        ;; it.
+        (let ((fstruct (htmlize-face-to-fstruct face)))
+          (setf (gethash face face-map) fstruct)
+          (let* ((css-name (htmlize-fstruct-css-name fstruct))
+                 (new-name css-name)
+                 (i 0))
+            ;; Uniquify the face's css-name by using NAME-1, NAME-2,
+            ;; etc.
+            (while (member new-name css-names)
+              (setq new-name (format "%s-%s" css-name (cl-incf i))))
+            (unless (equal new-name css-name)
+              (setf (htmlize-fstruct-css-name fstruct) new-name))
+            (push new-name css-names)))))
+    face-map))
+
+(defun htmlize-unstringify-face (face)
+  "If FACE is a string, return it interned, otherwise return it unchanged."
+  (if (stringp face)
+      (intern face)
+    face))
+
+(defun htmlize-faces-in-buffer ()
+  "Return a list of faces used in the current buffer.
+This is the set of faces specified by the `face' text property and by buffer
+overlays that specify `face'."
+  (let (faces)
+    ;; Faces used by text properties.
+    (let ((pos (point-min)) face-prop next)
+      (while (< pos (point-max))
+        (setq face-prop (get-text-property pos 'face)
+              next (or (next-single-property-change pos 'face) (point-max)))
+        (setq faces (cl-nunion (htmlize-decode-face-prop face-prop)
+                               faces :test 'equal))
+        (setq pos next)))
+    ;; Faces used by overlays.
+    (dolist (overlay (overlays-in (point-min) (point-max)))
+      (let ((face-prop (overlay-get overlay 'face)))
+        (setq faces (cl-nunion (htmlize-decode-face-prop face-prop)
+                               faces :test 'equal))))
+    faces))
+
+;; htmlize-faces-at-point returns the faces in use at point.  The
+;; faces are sorted by increasing priority, i.e. the last face takes
+;; precedence.
+;;
+;; This returns all the faces in the `face' property and all the faces
+;; in the overlays at point.
+
+(defun htmlize-faces-at-point ()
+  (let (all-faces)
+    ;; Faces from text properties.
+    (let ((face-prop (get-text-property (point) 'face)))
+      ;; we need to reverse the `face' prop because we want
+      ;; more specific faces to come later
+      (setq all-faces (nreverse (htmlize-decode-face-prop face-prop))))
+    ;; Faces from overlays.
+    (let ((overlays
+           ;; Collect overlays at point that specify `face'.
+           (cl-delete-if-not (lambda (o)
+                               (overlay-get o 'face))
+                             (nreverse (overlays-at (point) t))))
+          list face-prop)
+      (dolist (overlay overlays)
+        (setq face-prop (overlay-get overlay 'face)
+              list (nconc (htmlize-decode-face-prop face-prop) list)))
+      ;; Under "Merging Faces" the manual explicitly states
+      ;; that faces specified by overlays take precedence over
+      ;; faces specified by text properties.
+      (setq all-faces (nconc all-faces list)))
+    all-faces))
+
+;; htmlize supports generating HTML in several flavors, some of which
+;; use CSS, and others the <font> element.  We take an OO approach and
+;; define "methods" that indirect to the functions that depend on
+;; `htmlize-output-type'.  The currently used methods are `doctype',
+;; `insert-head', `body-tag', `pre-tag', and `text-markup'.  Not all
+;; output types define all methods.
+;;
+;; Methods are called either with (htmlize-method METHOD ARGS...)
+;; special form, or by accessing the function with
+;; (htmlize-method-function 'METHOD) and calling (funcall FUNCTION).
+;; The latter form is useful in tight loops because `htmlize-method'
+;; conses.
+
+(defmacro htmlize-method (method &rest args)
+  ;; Expand to (htmlize-TYPE-METHOD ...ARGS...).  TYPE is the value of
+  ;; `htmlize-output-type' at run time.
+  `(funcall (htmlize-method-function ',method) ,@args))
+
+(defun htmlize-method-function (method)
+  ;; Return METHOD's function definition for the current output type.
+  ;; The returned object can be safely funcalled.
+  (let ((sym (intern (format "htmlize-%s-%s" htmlize-output-type method))))
+    (indirect-function (if (fboundp sym)
+                           sym
+                         (let ((default (intern (concat "htmlize-default-"
+                                                        (symbol-name method)))))
+                           (if (fboundp default)
+                               default
+                             'ignore))))))
+
+(defvar htmlize-memoization-table (make-hash-table :test 'equal))
+
+(defmacro htmlize-memoize (key generator)
+  "Return the value of GENERATOR, memoized as KEY.
+That means that GENERATOR will be evaluated and returned the first time
+it's called with the same value of KEY.  All other times, the cached
+\(memoized) value will be returned."
+  (let ((value (cl-gensym)))
+    `(let ((,value (gethash ,key htmlize-memoization-table)))
+       (unless ,value
+         (setq ,value ,generator)
+         (setf (gethash ,key htmlize-memoization-table) ,value))
+       ,value)))
+
+;;; Default methods.
+
+(defun htmlize-default-doctype ()
+  nil                                   ; no doc-string
+  ;; Note that the `font' output is technically invalid under this DTD
+  ;; because the DTD doesn't allow embedding <font> in <pre>.
+  "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">"
+  )
+
+(defun htmlize-default-body-tag (face-map)
+  nil                                   ; no doc-string
+  face-map ; shut up the byte-compiler
+  "<body>")
+
+(defun htmlize-default-pre-tag (face-map)
+  nil                                   ; no doc-string
+  face-map ; shut up the byte-compiler
+  "<pre>")
+
+
+;;; CSS based output support.
+
+;; Internal function; not a method.
+(defun htmlize-css-specs (fstruct)
+  (let (result)
+    (when (htmlize-fstruct-foreground fstruct)
+      (push (format "color: %s;" (htmlize-fstruct-foreground fstruct))
+            result))
+    (when (htmlize-fstruct-background fstruct)
+      (push (format "background-color: %s;"
+                    (htmlize-fstruct-background fstruct))
+            result))
+    (let ((size (htmlize-fstruct-size fstruct)))
+      (when (and size (not (eq htmlize-ignore-face-size t)))
+        (cond ((floatp size)
+               (push (format "font-size: %d%%;" (* 100 size)) result))
+              ((not (eq htmlize-ignore-face-size 'absolute))
+               (push (format "font-size: %spt;" (/ size 10.0)) result)))))
+    (when (htmlize-fstruct-boldp fstruct)
+      (push "font-weight: bold;" result))
+    (when (htmlize-fstruct-italicp fstruct)
+      (push "font-style: italic;" result))
+    (when (htmlize-fstruct-underlinep fstruct)
+      (push "text-decoration: underline;" result))
+    (when (htmlize-fstruct-overlinep fstruct)
+      (push "text-decoration: overline;" result))
+    (when (htmlize-fstruct-strikep fstruct)
+      (push "text-decoration: line-through;" result))
+    (nreverse result)))
+
+(defun htmlize-css-insert-head (buffer-faces face-map)
+  (insert "    <style type=\"text/css\">\n    <!--\n")
+  (insert "      body {\n        "
+          (mapconcat #'identity
+                     (htmlize-css-specs (gethash 'default face-map))
+                     "\n        ")
+          "\n      }\n")
+  (dolist (face (cl-sort (cl-copy-list buffer-faces) #'string-lessp
+                         :key (lambda (f)
+                                (htmlize-fstruct-css-name
+                                 (gethash f face-map)))))
+    (let* ((fstruct (gethash face face-map))
+           (cleaned-up-face-name
+            (let ((s
+                   ;; Use `prin1-to-string' rather than `symbol-name'
+                   ;; to get the face name because the "face" can also
+                   ;; be an attrlist, which is not a symbol.
+                   (prin1-to-string face)))
+              ;; If the name contains `--' or `*/', remove them.
+              (while (string-match "--" s)
+                (setq s (replace-match "-" t t s)))
+              (while (string-match "\\*/" s)
+                (setq s (replace-match "XX" t t s)))
+              s))
+           (specs (htmlize-css-specs fstruct)))
+      (insert "      ." (htmlize-fstruct-css-name fstruct))
+      (if (null specs)
+          (insert " {")
+        (insert " {\n        /* " cleaned-up-face-name " */\n        "
+                (mapconcat #'identity specs "\n        ")))
+      (insert "\n      }\n")))
+  (insert htmlize-hyperlink-style
+          "    -->\n    </style>\n"))
+
+(defun htmlize-css-text-markup (fstruct-list buffer)
+  ;; Open the markup needed to insert text colored with FACES into
+  ;; BUFFER.  Return the function that closes the markup.
+
+  ;; In CSS mode, this is easy: just nest the text in one <span
+  ;; class=...> tag for each face in FSTRUCT-LIST.
+  (dolist (fstruct fstruct-list)
+    (princ "<span class=\"" buffer)
+    (princ (htmlize-fstruct-css-name fstruct) buffer)
+    (princ "\">" buffer))
+  (htmlize-lexlet ((fstruct-list fstruct-list) (buffer buffer))
+    (lambda ()
+      (dolist (fstruct fstruct-list)
+        (ignore fstruct)                ; shut up the byte-compiler
+        (princ "</span>" buffer)))))
+
+;; `inline-css' output support.
+
+(defun htmlize-inline-css-body-tag (face-map)
+  (format "<body style=\"%s\">"
+          (mapconcat #'identity (htmlize-css-specs (gethash 'default face-map))
+                     " ")))
+
+(defun htmlize-inline-css-pre-tag (face-map)
+  (if htmlize-pre-style
+      (format "<pre style=\"%s\">"
+              (mapconcat #'identity
+                         (htmlize-css-specs (gethash 'default face-map))
+                         " "))
+    (format "<pre>")))
+
+(defun htmlize-inline-css-text-markup (fstruct-list buffer)
+  (let* ((merged (htmlize-merge-faces fstruct-list))
+         (style (htmlize-memoize
+                 merged
+                 (let ((specs (htmlize-css-specs merged)))
+                   (and specs
+                        (mapconcat #'identity
+                                   (htmlize-css-specs merged)
+                                   " "))))))
+    (when style
+      (princ "<span style=\"" buffer)
+      (princ style buffer)
+      (princ "\">" buffer))
+    (htmlize-lexlet ((style style) (buffer buffer))
+      (lambda ()
+        (when style
+          (princ "</span>" buffer))))))
+
+;;; `font' tag based output support.
+
+(defun htmlize-font-body-tag (face-map)
+  (let ((fstruct (gethash 'default face-map)))
+    (format "<body text=\"%s\" bgcolor=\"%s\">"
+            (htmlize-fstruct-foreground fstruct)
+            (htmlize-fstruct-background fstruct))))
+
+(defun htmlize-font-pre-tag (face-map)
+  (if htmlize-pre-style
+      (let ((fstruct (gethash 'default face-map)))
+        (format "<pre text=\"%s\" bgcolor=\"%s\">"
+                (htmlize-fstruct-foreground fstruct)
+                (htmlize-fstruct-background fstruct)))
+    (format "<pre>")))
+
+(defun htmlize-font-text-markup (fstruct-list buffer)
+  ;; In `font' mode, we use the traditional HTML means of altering
+  ;; presentation: <font> tag for colors, <b> for bold, <u> for
+  ;; underline, and <strike> for strike-through.
+  (let* ((merged (htmlize-merge-faces fstruct-list))
+         (markup (htmlize-memoize
+                  merged
+                  (cons (concat
+                         (and (htmlize-fstruct-foreground merged)
+                              (format "<font color=\"%s\">"
+                                      (htmlize-fstruct-foreground merged)))
+                         (and (htmlize-fstruct-boldp merged)      "<b>")
+                         (and (htmlize-fstruct-italicp merged)    "<i>")
+                         (and (htmlize-fstruct-underlinep merged) "<u>")
+                         (and (htmlize-fstruct-strikep merged)    "<strike>"))
+                        (concat
+                         (and (htmlize-fstruct-strikep merged)    "</strike>")
+                         (and (htmlize-fstruct-underlinep merged) "</u>")
+                         (and (htmlize-fstruct-italicp merged)    "</i>")
+                         (and (htmlize-fstruct-boldp merged)      "</b>")
+                         (and (htmlize-fstruct-foreground merged) "</font>"))))))
+    (princ (car markup) buffer)
+    (htmlize-lexlet ((markup markup) (buffer buffer))
+      (lambda ()
+        (princ (cdr markup) buffer)))))
+
+(defun htmlize-buffer-1 ()
+  ;; Internal function; don't call it from outside this file.  Htmlize
+  ;; current buffer, writing the resulting HTML to a new buffer, and
+  ;; return it.  Unlike htmlize-buffer, this doesn't change current
+  ;; buffer or use switch-to-buffer.
+  (save-excursion
+    ;; Protect against the hook changing the current buffer.
+    (save-excursion
+      (run-hooks 'htmlize-before-hook))
+    ;; Convince font-lock support modes to fontify the entire buffer
+    ;; in advance.
+    (htmlize-ensure-fontified)
+    (clrhash htmlize-extended-character-cache)
+    (clrhash htmlize-memoization-table)
+    ;; It's important that the new buffer inherits default-directory
+    ;; from the current buffer.
+    (let ((htmlbuf (generate-new-buffer (if (buffer-file-name)
+                                            (htmlize-make-file-name
+                                             (file-name-nondirectory
+                                              (buffer-file-name)))
+                                          "*html*")))
+          (completed nil))
+      (unwind-protect
+          (let* ((buffer-faces (htmlize-faces-in-buffer))
+                 (face-map (htmlize-make-face-map
+                            (cl-adjoin 'default buffer-faces)))
+                 (places (cl-gensym))
+                 (title (if (buffer-file-name)
+                            (file-name-nondirectory (buffer-file-name))
+                          (buffer-name))))
+            (when htmlize-generate-hyperlinks
+              (htmlize-create-auto-links))
+            (when htmlize-replace-form-feeds
+              (htmlize-shadow-form-feeds))
+
+            ;; Initialize HTMLBUF and insert the HTML prolog.
+            (with-current-buffer htmlbuf
+              (buffer-disable-undo)
+              (insert (htmlize-method doctype) ?\n
+                      (format "<!-- Created by htmlize-%s in %s mode. -->\n"
+                              htmlize-version htmlize-output-type)
+                      "<html>\n  ")
+              (put places 'head-start (point-marker))
+              (insert "<head>\n"
+                      "    <title>" (htmlize-protect-string title) "</title>\n"
+                      (if htmlize-html-charset
+                          (format
+                           (concat "    <meta http-equiv=\"Content-Type\" "
+                                   "content=\"text/html; charset=%s\">\n")
+                           htmlize-html-charset)
+                        "")
+                      htmlize-head-tags)
+              (htmlize-method insert-head buffer-faces face-map)
+              (insert "  </head>")
+              (put places 'head-end (point-marker))
+              (insert "\n  ")
+              (put places 'body-start (point-marker))
+              (insert (htmlize-method body-tag face-map)
+                      "\n    ")
+              (put places 'content-start (point-marker))
+              (insert (htmlize-method pre-tag face-map) "\n"))
+            (let ((text-markup
+                   ;; Get the inserter method, so we can funcall it inside
+                   ;; the loop.  Not calling `htmlize-method' in the loop
+                   ;; body yields a measurable speed increase.
+                   (htmlize-method-function 'text-markup))
+                  ;; Declare variables used in loop body outside the loop
+                  ;; because it's faster to establish `let' bindings only
+                  ;; once.
+                  next-change text face-list trailing-ellipsis
+                  fstruct-list last-fstruct-list
+                  (close-markup (lambda ())))
+              ;; This loop traverses and reads the source buffer, appending
+              ;; the resulting HTML to HTMLBUF.  This method is fast
+              ;; because: 1) it doesn't require examining the text
+              ;; properties char by char (htmlize-next-face-change is used
+              ;; to move between runs with the same face), and 2) it doesn't
+              ;; require frequent buffer switches, which are slow because
+              ;; they rebind all buffer-local vars.
+              (goto-char (point-min))
+              (while (not (eobp))
+                (setq next-change (htmlize-next-face-change (point)))
+                ;; Get faces in use between (point) and NEXT-CHANGE, and
+                ;; convert them to fstructs.
+                (setq face-list (htmlize-faces-at-point)
+                      fstruct-list (delq nil (mapcar (lambda (f)
+                                                       (gethash f face-map))
+                                                     face-list)))
+                (cl-multiple-value-setq (text trailing-ellipsis)
+                  (htmlize-extract-text (point) next-change trailing-ellipsis))
+                ;; Don't bother writing anything if there's no text (this
+                ;; happens in invisible regions).
+                (when (> (length text) 0)
+                  ;; Open the new markup if necessary and insert the text.
+                  (when (not (cl-equalp fstruct-list last-fstruct-list))
+                    (funcall close-markup)
+                    (setq last-fstruct-list fstruct-list)
+                    (setq close-markup
+                          (funcall text-markup fstruct-list htmlbuf)))
+                  (princ text htmlbuf))
+                (goto-char next-change))
+
+              ;; We've gone through the buffer; close the markup from
+              ;; the last run, if any.
+              (funcall close-markup))
+
+            ;; Insert the epilog and post-process the buffer.
+            (with-current-buffer htmlbuf
+              (insert "</pre>")
+              (put places 'content-end (point-marker))
+              (insert "\n  </body>")
+              (put places 'body-end (point-marker))
+              (insert "\n</html>\n")
+              (htmlize-defang-local-variables)
+              (goto-char (point-min))
+              (when htmlize-html-major-mode
+                ;; What sucks about this is that the minor modes, most notably
+                ;; font-lock-mode, won't be initialized.  Oh well.
+                (funcall htmlize-html-major-mode))
+              (set (make-local-variable 'htmlize-buffer-places)
+                   (symbol-plist places))
+              (run-hooks 'htmlize-after-hook)
+              (buffer-enable-undo))
+            (setq completed t)
+            htmlbuf)
+
+        (when (not completed)
+          (kill-buffer htmlbuf))
+        (htmlize-delete-tmp-overlays)))))
+
+;; Utility functions.
+
+(defmacro htmlize-with-fontify-message (&rest body)
+  ;; When forcing fontification of large buffers in
+  ;; htmlize-ensure-fontified, inform the user that he is waiting for
+  ;; font-lock, not for htmlize to finish.
+  `(progn
+     (if (> (buffer-size) 65536)
+         (message "Forcing fontification of %s..."
+                  (buffer-name (current-buffer))))
+     ,@body
+     (if (> (buffer-size) 65536)
+         (message "Forcing fontification of %s...done"
+                  (buffer-name (current-buffer))))))
+
+(defun htmlize-ensure-fontified ()
+  ;; If font-lock is being used, ensure that the "support" modes
+  ;; actually fontify the buffer.  If font-lock is not in use, we
+  ;; don't care because, except in htmlize-file, we don't force
+  ;; font-lock on the user.
+  (when font-lock-mode
+    ;; In part taken from ps-print-ensure-fontified in GNU Emacs 21.
+    (when (and (boundp 'jit-lock-mode)
+               (symbol-value 'jit-lock-mode))
+      (htmlize-with-fontify-message
+       (jit-lock-fontify-now (point-min) (point-max))))
+
+    (if (fboundp 'font-lock-ensure)
+        (font-lock-ensure)
+      ;; Emacs prior to 25.1
+      (with-no-warnings
+        (font-lock-mode 1)
+        (font-lock-fontify-buffer)))))
+
+
+;;;###autoload
+(defun htmlize-buffer (&optional buffer interactive)
+  "Convert BUFFER to HTML, preserving colors and decorations.
+
+The generated HTML is available in a new buffer, which is returned.
+When invoked interactively (or if optional INTERACTIVE is non-nil),
+the new buffer is selected in the current window.  The title of the
+generated document will be set to the buffer's file name or, if that
+is not available, to the buffer's name.
+
+Note that htmlize doesn't fontify your buffers, it only uses the
+decorations that are already present.  If you don't set up font-lock or
+something else to fontify your buffers, the resulting HTML will be
+plain.  Likewise, if you don't like the choice of colors, fix the mode
+that created them, or simply alter the faces it uses."
+  (interactive "i\np")
+  (let ((htmlbuf (with-current-buffer (or buffer (current-buffer))
+                   (htmlize-buffer-1))))
+    (when interactive
+      (switch-to-buffer htmlbuf))
+    htmlbuf))
+
+;;;###autoload
+(defun htmlize-region (beg end &optional interactive)
+  "Convert the region to HTML, preserving colors and decorations.
+See `htmlize-buffer' for details."
+  (interactive "r\np")
+  ;; Don't let zmacs region highlighting end up in HTML.
+  (when (fboundp 'zmacs-deactivate-region)
+    (zmacs-deactivate-region))
+  (let ((htmlbuf (save-restriction
+                   (narrow-to-region beg end)
+                   (htmlize-buffer-1))))
+    (when interactive
+      (switch-to-buffer htmlbuf))
+    htmlbuf))
+
+(defun htmlize-region-for-paste (beg end)
+  "Htmlize the region and return just the HTML as a string.
+This forces the `inline-css' style and only returns the HTML body,
+but without the BODY tag.  This should make it useful for inserting
+the text to another HTML buffer."
+  (let* ((htmlize-output-type 'inline-css)
+         (htmlbuf (htmlize-region beg end)))
+    (unwind-protect
+        (with-current-buffer htmlbuf
+          (buffer-substring (plist-get htmlize-buffer-places 'content-start)
+                            (plist-get htmlize-buffer-places 'content-end)))
+      (kill-buffer htmlbuf))))
+
+(defun htmlize-region-save-screenshot (beg end)
+  "Save the htmlized (see `htmlize-region-for-paste') region in
+the kill ring. Uses `inline-css', with style information in
+`<pre>' tags, so that the rendering of the marked up text
+approximates the buffer as closely as possible."
+  (interactive "r")
+  (let ((htmlize-pre-style t))
+    (kill-new (htmlize-region-for-paste beg end)))
+  (deactivate-mark))
+
+(defun htmlize-make-file-name (file)
+  "Make an HTML file name from FILE.
+
+In its default implementation, this simply appends `.html' to FILE.
+This function is called by htmlize to create the buffer file name, and
+by `htmlize-file' to create the target file name.
+
+More elaborate transformations are conceivable, such as changing FILE's
+extension to `.html' (\"file.c\" -> \"file.html\").  If you want them,
+overload this function to do it and htmlize will comply."
+  (concat file ".html"))
+
+;; Older implementation of htmlize-make-file-name that changes FILE's
+;; extension to ".html".
+;; (defun htmlize-make-file-name (file)
+;;  (let ((extension (file-name-extension file))
+;;      (sans-extension (file-name-sans-extension file)))
+;;    (if (or (equal extension "html")
+;;          (equal extension "htm")
+;;          (equal sans-extension ""))
+;;      (concat file ".html")
+;;      (concat sans-extension ".html"))))
+
+;;;###autoload
+(defun htmlize-file (file &optional target)
+  "Load FILE, fontify it, convert it to HTML, and save the result.
+
+Contents of FILE are inserted into a temporary buffer, whose major mode
+is set with `normal-mode' as appropriate for the file type.  The buffer
+is subsequently fontified with `font-lock' and converted to HTML.  Note
+that, unlike `htmlize-buffer', this function explicitly turns on
+font-lock.  If a form of highlighting other than font-lock is desired,
+please use `htmlize-buffer' directly on buffers so highlighted.
+
+Buffers currently visiting FILE are unaffected by this function.  The
+function does not change current buffer or move the point.
+
+If TARGET is specified and names a directory, the resulting file will be
+saved there instead of to FILE's directory.  If TARGET is specified and
+does not name a directory, it will be used as output file name."
+  (interactive (list (read-file-name
+                      "HTML-ize file: "
+                      nil nil nil (and (buffer-file-name)
+                                       (file-name-nondirectory
+                                        (buffer-file-name))))))
+  (let ((output-file (if (and target (not (file-directory-p target)))
+                         target
+                       (expand-file-name
+                        (htmlize-make-file-name (file-name-nondirectory file))
+                        (or target (file-name-directory file)))))
+        ;; Try to prevent `find-file-noselect' from triggering
+        ;; font-lock because we'll fontify explicitly below.
+        (font-lock-mode nil)
+        (font-lock-auto-fontify nil)
+        (global-font-lock-mode nil))
+    (with-temp-buffer
+      ;; Insert FILE into the temporary buffer.
+      (insert-file-contents file)
+      ;; Set the file name so normal-mode and htmlize-buffer-1 pick it
+      ;; up.  Restore it afterwards so with-temp-buffer's kill-buffer
+      ;; doesn't complain about killing a modified buffer.
+      (let ((buffer-file-name file))
+        ;; Set the major mode for the sake of font-lock.
+        (normal-mode)
+        ;; htmlize the buffer and save the HTML.
+        (with-current-buffer (htmlize-buffer-1)
+          (unwind-protect
+              (progn
+                (run-hooks 'htmlize-file-hook)
+                (write-region (point-min) (point-max) output-file))
+            (kill-buffer (current-buffer)))))))
+  ;; I haven't decided on a useful return value yet, so just return
+  ;; nil.
+  nil)
+
+;;;###autoload
+(defun htmlize-many-files (files &optional target-directory)
+  "Convert FILES to HTML and save the corresponding HTML versions.
+
+FILES should be a list of file names to convert.  This function calls
+`htmlize-file' on each file; see that function for details.  When
+invoked interactively, you are prompted for a list of files to convert,
+terminated with RET.
+
+If TARGET-DIRECTORY is specified, the HTML files will be saved to that
+directory.  Normally, each HTML file is saved to the directory of the
+corresponding source file."
+  (interactive
+   (list
+    (let (list file)
+      ;; Use empty string as DEFAULT because setting DEFAULT to nil
+      ;; defaults to the directory name, which is not what we want.
+      (while (not (equal (setq file (read-file-name
+                                     "HTML-ize file (RET to finish): "
+                                     (and list (file-name-directory
+                                                (car list)))
+                                     "" t))
+                         ""))
+        (push file list))
+      (nreverse list))))
+  ;; Verify that TARGET-DIRECTORY is indeed a directory.  If it's a
+  ;; file, htmlize-file will use it as target, and that doesn't make
+  ;; sense.
+  (and target-directory
+       (not (file-directory-p target-directory))
+       (error "target-directory must name a directory: %s" target-directory))
+  (dolist (file files)
+    (htmlize-file file target-directory)))
+
+(declare-function dired-get-marked-files "dired"
+                  (&optional localp arg filter distinguish-one-marked error))
+
+;;;###autoload
+(defun htmlize-many-files-dired (arg &optional target-directory)
+  "HTMLize dired-marked files."
+  (interactive "P")
+  (htmlize-many-files (dired-get-marked-files nil arg) target-directory))
+
+(provide 'htmlize)
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; htmlize.el ends here
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..3d560ab
--- /dev/null
+++ b/index.html
@@ -0,0 +1,4138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Shell Field Guide</title>
+<meta name="generator" content="Org mode" />
+<meta name="author" content="Raimon Grau" />
+<meta name="keywords" content="bash zsh shell" />
+<link rel="stylesheet" type="text/css" href="https://fniessen.github.io/org-html-themes/src/readtheorg_theme/css/htmlize.css"/>
+<link rel="stylesheet" type="text/css" href="https://fniessen.github.io/org-html-themes/src/readtheorg_theme/css/readtheorg.css"/>
+<link rel="stylesheet" type="text/css" href="src/readtheorg_theme/css/search.css"/>
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+<script type="text/javascript" src="https://fniessen.github.io/org-html-themes/src/lib/js/jquery.stickytableheaders.min.js"></script>
+<script type="text/javascript" src="https://fniessen.github.io/org-html-themes/src/readtheorg_theme/js/search.js"></script>
+<script type="text/javascript" src="https://fniessen.github.io/org-html-themes/src/readtheorg_theme/js/readtheorg.js"></script>
+<link rel="stylesheet" type="text/css" href="styles.css"/>
+<script type="text/javascript">
+/*
+@licstart  The following is the entire license notice for the
+JavaScript code in this tag.
+
+Copyright (C) 2012-2018 Free Software Foundation, Inc.
+
+The JavaScript code in this tag is free software: you can
+redistribute it and/or modify it under the terms of the GNU
+General Public License (GNU GPL) as published by the Free Software
+Foundation, either version 3 of the License, or (at your option)
+any later version.  The code is distributed WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
+
+As additional permission under GNU GPL version 3 section 7, you
+may distribute non-source (e.g., minimized or compacted) forms of
+that code without the copy of the GNU GPL normally required by
+section 4, provided you include this license notice and a URL
+through which recipients can access the Corresponding Source.
+
+
+@licend  The above is the entire license notice
+for the JavaScript code in this tag.
+*/
+<!--/*--><![CDATA[/*><!--*/
+ function CodeHighlightOn(elem, id)
+ {
+   var target = document.getElementById(id);
+   if(null != target) {
+     elem.cacheClassElem = elem.className;
+     elem.cacheClassTarget = target.className;
+     target.className = "code-highlighted";
+     elem.className   = "code-highlighted";
+   }
+ }
+ function CodeHighlightOff(elem, id)
+ {
+   var target = document.getElementById(id);
+   if(elem.cacheClassElem)
+     elem.className = elem.cacheClassElem;
+   if(elem.cacheClassTarget)
+     target.className = elem.cacheClassTarget;
+ }
+/*]]>*///-->
+</script>
+<script type="text/x-mathjax-config">
+    MathJax.Hub.Config({
+        displayAlign: "center",
+        displayIndent: "0em",
+
+        "HTML-CSS": { scale: 100,
+                        linebreaks: { automatic: "false" },
+                        webFont: "TeX"
+                       },
+        SVG: {scale: 100,
+              linebreaks: { automatic: "false" },
+              font: "TeX"},
+        NativeMML: {scale: 100},
+        TeX: { equationNumbers: {autoNumber: "AMS"},
+               MultLineWidth: "85%",
+               TagSide: "right",
+               TagIndent: ".8em"
+             }
+});
+</script>
+<script type="text/javascript"
+        src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML"></script>
+</head>
+<body>
+<div id="content">
+<h1 class="title">Shell Field Guide</h1>
+<div id="table-of-contents">
+<h2>Table of Contents</h2>
+<div id="text-table-of-contents">
+<ul>
+<li><a href="#org519edc0">1. Introduction</a></li>
+<li><a href="#org3423cd9">2. Which Shell?</a></li>
+<li><a href="#org8627e30">3. Level</a></li>
+<li><a href="#org03577b7">4. Patterns</a>
+<ul>
+<li><a href="#org4cea4a4">4.1. Use Shellcheck</a></li>
+<li><a href="#orgb23ad11">4.2. Booleans and Conditionals</a></li>
+<li><a href="#org2a54087">4.3. Arrays</a></li>
+<li><a href="#orgff80d8d">4.4. Pass Arrays around</a></li>
+<li><a href="#org611f3ec">4.5. Slurping arrays</a></li>
+<li><a href="#orge9fd7eb">4.6. Array slices</a></li>
+<li><a href="#org7bfc5d6">4.7. Read lines from file</a></li>
+<li><a href="#org537337f">4.8. Assign to $1,$2,$3&#x2026;</a></li>
+<li><a href="#orgce97751">4.9. Functions</a></li>
+<li><a href="#orgf214d89">4.10. Variables</a></li>
+<li><a href="#orgef7cc9b">4.11. Variable/Parameter Expansions</a></li>
+<li><a href="#org47ba6ce">4.12. Conditional Expansion</a></li>
+<li><a href="#org9aebe6f">4.13. Interpolation</a></li>
+<li><a href="#orga9ed6bc">4.14. dispatch functions using args</a></li>
+<li><a href="#orgb7858eb">4.15. command_not_found_handle</a></li>
+<li><a href="#orgb5e6212">4.16. Return Values for Conditionals</a></li>
+<li><a href="#org54df9a7">4.17. set variable in an "if" test</a></li>
+<li><a href="#org2b61f9c">4.18. Do work on loop conditions</a></li>
+<li><a href="#org18dee81">4.19. One Branch Conditionals</a></li>
+<li><a href="#orgfbef4b5">4.20. pushd/popd</a></li>
+<li><a href="#org7423475">4.21. wrap functions</a></li>
+<li><a href="#org7ef1223">4.22. use [[</a></li>
+<li><a href="#orgee706c0">4.23. eval?</a></li>
+<li><a href="#org02c12cf">4.24. pass commands around</a></li>
+<li><a href="#org56dd1ec">4.25. The Toplevel Is Hopeless</a></li>
+<li><a href="#orgf392454">4.26. Check your deps</a></li>
+<li><a href="#org3ffffeb">4.27. source files</a></li>
+<li><a href="#orgb88dd1f">4.28. Use Scripts as a Libs</a></li>
+<li><a href="#orgde4ff58">4.29. Tmpfiles Everywhere</a></li>
+<li><a href="#orgbb023dc">4.30. Cleanup tasks with trap</a></li>
+<li><a href="#org36bb32c">4.31. array of callbacks on_exit</a></li>
+<li><a href="#org2fe2244">4.32. stacktrace on error</a></li>
+<li><a href="#org42e5305">4.33. Dots and colons allowed in function names!</a></li>
+<li><a href="#org212b4c0">4.34. make steps of the process as composable as possible by using "$@"</a></li>
+<li><a href="#orgb37df27">4.35. do_times/foreach_*</a></li>
+<li><a href="#orgdafc152">4.36. &lt;(foo) and &gt;(foo)</a></li>
+<li><a href="#orgb79e87a">4.37. Modify behavior by linking files</a></li>
+<li><a href="#orgdde7c4f">4.38. Modify a file on the fly, without changing it on disk</a></li>
+<li><a href="#orgd157786">4.39. Use xargs</a></li>
+<li><a href="#orgbf1f66b">4.40. xargs + paste</a></li>
+<li><a href="#org58f56ac">4.41. paste?</a></li>
+<li><a href="#org132da2c">4.42. Scripts as filters</a></li>
+<li><a href="#org7c440a6">4.43. Read or print to stdin inside a pipe</a></li>
+<li><a href="#orge66f5c7">4.44. change loops for "mapping/reducing" functions</a>
+<ul>
+<li><a href="#org94f7fb3">4.44.1. find</a></li>
+<li><a href="#orgbaab8f7">4.44.2. grep -Fvf</a></li>
+<li><a href="#orgf574bc9">4.44.3. grep -Pzo</a></li>
+<li><a href="#orgba1c238">4.44.4. grep -Ec</a></li>
+<li><a href="#orgf97a3bf">4.44.5. Set operations</a></li>
+</ul>
+</li>
+<li><a href="#org47f30fe">4.45. jq</a></li>
+<li><a href="#orgb903038">4.46. use jq . &lt;&lt;&lt;"$var"</a></li>
+<li><a href="#orge18de62">4.47. pass flags as a splatted array</a></li>
+<li><a href="#org7b4909b">4.48. inherit_errexit</a></li>
+<li><a href="#org744078f">4.49. GNU Parallel</a></li>
+<li><a href="#orgf918892">4.50. HEREDOCS</a></li>
+<li><a href="#org9e3ae47">4.51. HERESTRINGS</a></li>
+<li><a href="#orge8c0901">4.52. __DATA__</a></li>
+<li><a href="#org1478364">4.53. Simple Templating</a></li>
+<li><a href="#org6deb5a1">4.54. Secrets</a></li>
+<li><a href="#org2e96f17">4.55. Escape single quotes in single quoted strings</a></li>
+<li><a href="#orgfe947dc">4.56. any, every, lambdas, closures, and eval</a></li>
+</ul>
+</li>
+<li><a href="#org85600a8">5. Interactive</a>
+<ul>
+<li><a href="#orgebc2ac7">5.1. Save your small scripts</a></li>
+<li><a href="#orgd03bc18">5.2. Increased Interactivity</a></li>
+<li><a href="#orgbc665f5">5.3. Aliases</a></li>
+<li><a href="#orgce75f2e">5.4. functions can generate aliases</a></li>
+<li><a href="#org85375f7">5.5. Override (advice?) common functions</a></li>
+<li><a href="#orgf1af6fd">5.6. Faster iteration on pipes</a></li>
+<li><a href="#org3709c91">5.7. Use ${var?error msg} on templates</a></li>
+<li><a href="#orgf8108b7">5.8. Idempotent functions</a>
+<ul>
+<li><a href="#org45726e5">5.8.1. nop subsequent calls</a></li>
+<li><a href="#orgce65206">5.8.2. Download once</a></li>
+<li><a href="#orgb384a40">5.8.3. memoize with ttl, with ttl</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li><a href="#org1d488c7">6. Debugging</a>
+<ul>
+<li><a href="#org766f8db">6.1. adding <code>bash</code> to a script to debug</a></li>
+<li><a href="#orgb9cc112">6.2. DRY_RUN</a></li>
+<li><a href="#org99348e1">6.3. Cheap debugging flag</a></li>
+<li><a href="#orgcde2971">6.4. explore a pipe with tee &gt;(some_command) |</a></li>
+<li><a href="#org3d85028">6.5. tee+sudo</a></li>
+<li><a href="#org4c63237">6.6. quoting</a></li>
+</ul>
+</li>
+<li><a href="#org34f68f7">7. zsh-only</a>
+<ul>
+<li><a href="#org2aae8cd">7.1. Word spliting</a></li>
+<li><a href="#orga4ecce6">7.2. globbing</a></li>
+<li><a href="#orga8080f2">7.3. Global aliases:</a></li>
+<li><a href="#org3746252">7.4. Expansion of global aliases</a></li>
+<li><a href="#org33f98b5">7.5. Autocomplete</a></li>
+<li><a href="#org0d3209d">7.6. Create helpers and generate global aliases automagically</a></li>
+<li><a href="#org5b1403e">7.7. suffix aliases don't have to match a filename</a></li>
+<li><a href="#org7a453b9">7.8. noglob</a></li>
+<li><a href="#org66a71b7">7.9. make noglob 'transparent' to bash</a></li>
+<li><a href="#orge0f04ad">7.10. glob nested expansion</a></li>
+<li><a href="#orga113df8">7.11. Some extra shortcuts for nice things</a></li>
+<li><a href="#org686bf61">7.12. =()</a></li>
+</ul>
+</li>
+<li><a href="#org691d1e2">8. <span class="todo TODO">TODO</span> patterns</a>
+<ul>
+<li><a href="#orgc1d8b98">8.1. just use cat/netcat/pipes with &lt;()</a>
+<ul>
+<li><a href="#org2e1e61c">8.1.1. what's the unifying theory behind all that?</a></li>
+</ul>
+</li>
+<li><a href="#org1056b1d">8.2. redirects &amp; streams</a></li>
+<li><a href="#org763dc7e">8.3. The $0 pattern</a></li>
+<li><a href="#org18b2ff5">8.4. use git staging area to diff outputs of commands</a></li>
+<li><a href="#orgeb2aacd">8.5. coprocs</a></li>
+</ul>
+</li>
+<li><a href="#org6331da9">9. links</a></li>
+<li><a href="#org434fe9d">10. From shell to lisp and everything in between</a></li>
+<li><a href="#org059781e">11. Credits</a></li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-org519edc0" class="outline-2">
+<h2 id="org519edc0"><span class="section-number-2">1</span> Introduction</h2>
+<div class="outline-text-2" id="text-1">
+<p>
+This booklet is intended to be a catalog of tricks and techniques
+you may want to use if you're doing some sort of complex
+scripting. Some are useful in "The Real World (TM)", some are more
+playful, and might not have such direct impact in your day-to-day
+life. Some are pure entertainment. You'll have to judge by yourself
+which belong to which. I'll try to keep the rhetoric to the minimum
+to maximize signal/noise.
+</p>
+
+<p>
+The git repo is at
+<a href="https://github.com/kidd/scripting-field-guide/">https://github.com/kidd/scripting-field-guide/</a>. Any feedback is
+greatly appreciated. Keep in mind this is not any kind of official
+doc. I just write MY current "state of the art" and I'll be updating
+the contents with useful stuff I find or discover, that are not
+widely explained in usual manuals/wikis.
+</p>
+
+<p>
+You surely have some amount of sh/bash/zsh in your stack that
+probably started as one-off scripts, and later grew and were
+copypasted everywhere in your pipelines, repos, coworkers' ~/bin, or
+your coworkers use for their own things (with some variations),
+etc. Those scripts are very difficult to kill and they have a very
+high mutation rate.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org3423cd9" class="outline-2">
+<h2 id="org3423cd9"><span class="section-number-2">2</span> Which Shell?</h2>
+<div class="outline-text-2" id="text-2">
+<p>
+No matter if you use Linux, Mac, or Windows, you should be living
+most of the time in a shell to enjoy the content shown here. Some
+value comes from running scripts, and some comes from the daily
+usage and refinement of your helper functions, aliases, etc. in
+interactive mode.
+</p>
+
+<p>
+In general the examples here are meant to run in Bash or Zsh, which
+are compatible for the most part.
+</p>
+</div>
+</div>
+<div id="outline-container-org8627e30" class="outline-2">
+<h2 id="org8627e30"><span class="section-number-2">3</span> Level</h2>
+<div class="outline-text-2" id="text-3">
+<p>
+These examples are based on non-trivial real world code I've written
+using patterns I haven't seen applied in many places over the net. A
+few of the snippets are stolen from public repos I find interesting.
+Also, important scripting stuff might be missing if I don't feel
+I have anything to add to the generally available info around.
+</p>
+</div>
+</div>
+<div id="outline-container-org03577b7" class="outline-2">
+<h2 id="org03577b7"><span class="section-number-2">4</span> Patterns</h2>
+<div class="outline-text-2" id="text-4">
+</div>
+<div id="outline-container-org4cea4a4" class="outline-3">
+<h3 id="org4cea4a4"><span class="section-number-3">4.1</span> Use Shellcheck</h3>
+<div class="outline-text-3" id="text-4-1">
+<p>
+First, let's get that out of the way. This is low-hanging
+fruit. And you will get the most of this booklet by following it.
+</p>
+
+<p>
+A lot of the most common errors we usually make are well known
+ones. And in fact, we all usually fail in similar ways. Bash is
+known for being error prone when dealing with testing variable
+values, string operations, or flaky subshells and pipes.
+</p>
+
+<p>
+Installing <a href="https://www.shellcheck.net/">shellcheck</a> will flag many of those ticking bombs for
+you.
+</p>
+
+<p>
+No matter which editor you are using, you should be able to
+install a plugin to do automatic checks while you're editing.
+</p>
+
+<p>
+In emacs' case, the package is called <a href="https://github.com/federicotdn/flymake-shellcheck">flymake-shellcheck</a>, and a
+quick configuration for it is:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-elisp">(use-package flymake-shellcheck
+  <span style="font-weight: bold;">:ensure</span> t
+  <span style="font-weight: bold;">:commands</span> flymake-shellcheck-load
+  <span style="font-weight: bold;">:init</span>
+  (add-hook 'sh-mode-hook 'flymake-shellcheck-load))
+</pre>
+</div>
+
+<p>
+Shellcheck is available on most distros, so it's just an <code>apt</code>,
+<code>brew</code>, or <code>nix-env</code> away.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgb23ad11" class="outline-3">
+<h3 id="orgb23ad11"><span class="section-number-3">4.2</span> Booleans and Conditionals</h3>
+<div class="outline-text-3" id="text-4-2">
+<p>
+In any shell, <code>foo &amp;&amp; bar</code> will execute <code>bar</code> only if <code>foo</code>
+succeeded. That means that <code>foo</code> returned 0. That means that to &amp;&amp;
+(which you read like "and"), 0 is true. so yes. 0 is true, and
+other values are false.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org2a54087" class="outline-3">
+<h3 id="org2a54087"><span class="section-number-3">4.3</span> Arrays</h3>
+<div class="outline-text-3" id="text-4-3">
+<p>
+Ordered list of things.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">foo</span>=(<span style="font-style: italic;">"ls"</span> <span style="font-style: italic;">"/tmp/"</span>)
+
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">foo</span>[-2]}
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">foo</span>[-1]}
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">foo</span>[0]}
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">foo</span>[1]}
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">foo</span>[2]}
+
+<span style="font-weight: bold;">for</span> i<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"${foo[@]}"</span>; <span style="font-weight: bold;">do</span>
+  <span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">i</span>
+<span style="font-weight: bold;">done</span>
+
+$<span style="font-weight: bold; font-style: italic;">foo</span>
+${<span style="font-weight: bold; font-style: italic;">foo</span>[*]}
+${<span style="font-weight: bold; font-style: italic;">foo</span>[@]}
+<span style="font-weight: bold;">echo</span> ${#<span style="font-weight: bold; font-style: italic;">foo</span>[*]}
+<span style="font-weight: bold;">echo</span> ${#<span style="font-weight: bold; font-style: italic;">foo</span>[@]}
+</pre>
+</div>
+
+<p>
+Are <code>*</code> and <code>@</code> equal? <a href="https://stackoverflow.com/questions/2761723/what-is-the-difference-between-and-in-shell-scripts">nope</a>.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-style: italic;">"${foo[@]}"</span>
+<span style="font-style: italic;">"${foo[*]}"</span>
+</pre>
+</div>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">!/bin/</span><span style="font-weight: bold;">bash</span>
+
+<span style="font-weight: bold;">main</span>()
+{
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'MAIN sees '</span> $<span style="font-weight: bold; font-style: italic;">#</span> <span style="font-style: italic;">' args'</span>
+}
+
+main $<span style="font-weight: bold; font-style: italic;">*</span>
+main $<span style="font-weight: bold; font-style: italic;">@</span>
+
+main <span style="font-style: italic;">"$*"</span>
+main <span style="font-style: italic;">"$@"</span>
+
+<span style="font-weight: bold; font-style: italic;">### </span><span style="font-weight: bold; font-style: italic;">end ###</span>
+</pre>
+</div>
+
+<p>
+and I run it like this:
+</p>
+
+<p>
+<code>my_script 'a b c' d e</code>
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgff80d8d" class="outline-3">
+<h3 id="orgff80d8d"><span class="section-number-3">4.4</span> Pass Arrays around</h3>
+<div class="outline-text-3" id="text-4-4">
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">a</span>=(<span style="font-style: italic;">'Track 01.mp3'</span> <span style="font-style: italic;">'Track 02.mp3'</span>)
+myfun <span style="font-style: italic;">"${a[@]}"</span> <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">pass array to a function</span>
+<span style="font-weight: bold; font-style: italic;">b</span>=( <span style="font-style: italic;">"${a[@]}"</span> ) <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">copy array</span>
+</pre>
+</div>
+
+<p>
+Read the great <a href="http://www.oilshell.org/blog/2016/11/06.html">Oil Shell blogpost</a>.
+</p>
+</div>
+</div>
+<div id="outline-container-org611f3ec" class="outline-3">
+<h3 id="org611f3ec"><span class="section-number-3">4.5</span> Slurping arrays</h3>
+<div class="outline-text-3" id="text-4-5">
+<p>
+A nice way to read a bunch of elements in one go is to use
+<code>readarray</code>.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">parse_args</span>() {
+  [[ $<span style="font-weight: bold; font-style: italic;">#</span> -eq 0 ]] &amp;&amp; die <span style="font-style: italic;">"Usage: $0 &lt;version&gt;"</span>
+  <span style="font-weight: bold; font-style: italic;">version</span>=<span style="font-style: italic;">"$1"</span>
+  local <span style="font-weight: bold; font-style: italic;">version_split</span>=$(<span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">version</span> | tr <span style="font-style: italic;">'.'</span> <span style="font-style: italic;">'\n'</span>)
+  readarray -t version_array &lt;&lt;&lt; <span style="font-style: italic;">"$version_split"</span>
+
+  <span style="font-weight: bold;">if</span> [[ -z ${<span style="font-weight: bold; font-style: italic;">version_array</span>[3]} ]]; <span style="font-weight: bold;">then</span>
+    die <span style="font-style: italic;">"not enough version numbers"</span>
+  <span style="font-weight: bold;">fi</span>
+}
+</pre>
+</div>
+
+<p>
+Even nicer would be to use IFS so we'd be able to split in one go.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">IFS</span>=. read -a ver &lt;&lt;&lt;<span style="font-style: italic;">"1.23.1.0"</span>
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">ver</span>[0]}
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"next/${ver[0]}.${ver[1]}.x.x"</span>
+</pre>
+</div>
+
+<p>
+Or, use it in a destructuring fashion:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">get_nix_version_parts</span>(){
+  local major minor patch
+  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">shellcheck disable=SC2034,SC2162</span>
+  <span style="font-weight: bold; font-style: italic;">IFS</span>=<span style="font-style: italic;">"."</span> read major minor patch &lt; &lt;(get_nix_version)
+  local -p
+}
+
+$ get_nix_version_parts
+<span style="font-weight: bold; font-style: italic;">major</span>=2
+<span style="font-weight: bold; font-style: italic;">minor</span>=3
+<span style="font-weight: bold; font-style: italic;">patch</span>=4
+</pre>
+</div>
+<p>
+<a href="https://news.ycombinator.com/item?id=24408318">https://news.ycombinator.com/item?id=24408318</a>
+</p>
+</div>
+</div>
+<div id="outline-container-orge9fd7eb" class="outline-3">
+<h3 id="orge9fd7eb"><span class="section-number-3">4.6</span> Array slices</h3>
+<div class="outline-text-3" id="text-4-6">
+<p>
+you can slice an array like this:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">a</span>=(a b c d e f g)
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"${a[@]:1}"</span>  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">tail of array</span>
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"${a[@]:1:2}"</span>  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">from that, take 2 elements</span>
+</pre>
+</div>
+
+<p>
+This is a <a href="https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html">parameter expansion</a>, same as <code>${a/foo/bar}</code> and similar
+replacements. As such, The <code>$@</code> and <code>$*</code> are treated a bit
+differently.
+</p>
+
+<p>
+Look at <code>${parameter:offset:length}</code> in the parameter expansion
+bash manual and be amazed by the specialcasing :).
+</p>
+
+<p>
+This concrete case is when the parameter is an indexed array name
+subscripted by '@' or '*'.
+</p>
+
+<p>
+Don't ask me why, but when the array is <code>$@</code>, it seems that it
+behaves a bit differently. It's 'explained' in that same part of
+the docs.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"> <span style="font-weight: bold; font-style: italic;">a</span>=(a b c d e f g)
+<span style="font-weight: bold;">foo</span>() {
+ <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"${@:2}"</span>  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">tail of array</span>
+ <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"${@:2:2}"</span>  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">from that, take 2 elements</span>
+}
+foo a b c d
+foo <span style="font-style: italic;">"${a[@]}"</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org7bfc5d6" class="outline-3">
+<h3 id="org7bfc5d6"><span class="section-number-3">4.7</span> Read lines from file</h3>
+<div class="outline-text-3" id="text-4-7">
+<p>
+The <code>read</code> command we used just above is part of the usual idiom to
+read a file line by line.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">while </span><span style="font-weight: bold;">read</span> -r line; <span style="font-weight: bold;">do</span>
+  <span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">line</span>
+<span style="font-weight: bold;">done</span> &lt; /tmp/file.txt
+</pre>
+</div>
+
+<p>
+More related info in the <a href="https://mywiki.wooledge.org/BashFAQ/001">BashFAQ001</a>. But it's very rare the case
+where I need to iterate a file line by line.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org537337f" class="outline-3">
+<h3 id="org537337f"><span class="section-number-3">4.8</span> Assign to $1,$2,$3&#x2026;</h3>
+<div class="outline-text-3" id="text-4-8">
+<p>
+<code>set --</code> can be used as an incantation to assign to the positional
+parameters. Let me show you.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">set</span> -- a b c
+<span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">1</span> $<span style="font-weight: bold; font-style: italic;">2</span> $<span style="font-weight: bold; font-style: italic;">3</span>
+<span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">@</span>
+</pre>
+</div>
+
+<p>
+See? here's how to "unshift" a parameter to the current arg list:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">set</span> -- <span style="font-style: italic;">"injected"</span> <span style="font-style: italic;">"$@"</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orgce97751" class="outline-3">
+<h3 id="orgce97751"><span class="section-number-3">4.9</span> Functions</h3>
+<div class="outline-text-3" id="text-4-9">
+<p>
+Functions are functions. They receive arguments, and they return a
+value.
+</p>
+
+<p>
+The special thing about shell functions is that they also can use
+the file descriptors of the process. That means that they "inherit"
+STDIN, STDOUT, STDERR (and maybe more).
+</p>
+
+<p>
+Use them.
+</p>
+
+<p>
+Another point is that function names can be passed as parameters,
+because they are passed as strings, but you can call them inside as
+functions again. Maybe they are better than you <a href="https://news.ycombinator.com/item?id=29058140">think.</a>
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">f</span>() {
+  $<span style="font-weight: bold; font-style: italic;">1</span> hi
+}
+
+f echo
+f touch <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">will create a file 'hi'</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orgf214d89" class="outline-3">
+<h3 id="orgf214d89"><span class="section-number-3">4.10</span> Variables</h3>
+<div class="outline-text-3" id="text-4-10">
+<p>
+By default variables are global, to a file. No matter if you assign
+them for the first time inside a function, or at the top level.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">foo</span>=3
+<span style="font-weight: bold; font-style: italic;">bar</span>=$<span style="font-weight: bold; font-style: italic;">foo</span>
+<span style="font-weight: bold;">f</span>() {
+  <span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">bar</span>
+}
+f
+</pre>
+</div>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">f</span>() {
+  <span style="font-weight: bold; font-style: italic;">bar</span>=1
+}
+f
+<span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">bar</span>
+</pre>
+</div>
+
+<p>
+You make a variable local to a function with <code>local</code>. Use it as
+much as you can (kinda obvious).
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">myfun</span>() {
+  local bar
+  <span style="font-weight: bold; font-style: italic;">bar</span>=3
+  <span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">bar</span>
+}
+
+<span style="font-weight: bold; font-style: italic;">bar</span>=4
+<span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">bar</span>
+myfun
+<span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">bar</span>
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-orgef7cc9b" class="outline-3">
+<h3 id="orgef7cc9b"><span class="section-number-3">4.11</span> Variable/Parameter Expansions</h3>
+<div class="outline-text-3" id="text-4-11">
+<p>
+They offer some variable manipulations using shell only, not having
+to create another process <code>sed,awk,perl</code>.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">v</span>=banana
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">substitute one</span>
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">v</span>/na/NA}   <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">baNAna</span>
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">substitute many</span>
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">v</span>//na/NA}  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">baNANA</span>
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">substitute from the start (think ^ in PCRE)</span>
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">v</span>/#ba/NA}  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">NAnana</span>
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">substitute from the end</span>
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">v</span>/%na/NA}  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">banaNA</span>
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">Capitalize</span>
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">v</span>^}  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">Banana</span>
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">Uppercase</span>
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">v</span>^^}  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">BANANA</span>
+</pre>
+</div>
+
+<p>
+Take a read on <a href="https://tldp.org/LDP/abs/html/manipulatingvars.html">https://tldp.org/LDP/abs/html/manipulatingvars.html</a>
+and
+<a href="https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html">https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html</a>
+for more details.
+</p>
+
+<p>
+And a nice non-obvious trick from here is to prefix or suffix a
+variable string:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">v</span>=banana
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">v</span>/%/na}   <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">bananana</span>
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">v</span>/#/na}   <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">nabanana</span>
+</pre>
+</div>
+
+<p>
+And a less obvious trick is to prefix every element of an array
+with a fixed string:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">local <span style="font-weight: bold; font-style: italic;">arr</span>=(<span style="font-weight: bold; font-style: italic;">var1</span>=1 <span style="font-weight: bold; font-style: italic;">var2</span>=2)
+<span style="font-weight: bold;">echo</span> ${<span style="font-weight: bold; font-style: italic;">arr</span>[*]/#/<span style="font-style: italic;">"--env "</span>}
+</pre>
+</div>
+
+<p>
+This will produce <code>--env var1=1 --env var2=2</code>.  Super useful to be
+combined when building flags for docker.
+</p>
+
+<p>
+Another nice trick is a portable <code>realpath $PWD</code> with <code>${0%/*}</code>,
+which I found in <a href="https://github.com/picolisp/pil21/blob/master/vip">picolisp's vip</a>:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">!/bin/</span><span style="font-weight: bold;">sh</span>
+<span style="font-weight: bold;">exec</span> ${<span style="font-weight: bold; font-style: italic;">0</span>%/*}/bin/picolisp ${<span style="font-weight: bold; font-style: italic;">0</span>%/*}/lib.l @bin/vip <span style="font-style: italic;">"$@"</span>
+</pre>
+</div>
+
+<p>
+<code>${0%/*}/bin/picolisp</code> will replace keep the path of the current
+script and append <code>/bin/picolisp</code>. A cool way to get a realpath.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org47ba6ce" class="outline-3">
+<h3 id="org47ba6ce"><span class="section-number-3">4.12</span> Conditional Expansion</h3>
+<div class="outline-text-3" id="text-4-12">
+<div class="org-src-container">
+<pre class="src src-bash">local  <span style="font-weight: bold; font-style: italic;">foo</span>=${<span style="font-weight: bold; font-style: italic;">var</span>:-${<span style="font-weight: bold; font-style: italic;">default</span>:-}}
+local  <span style="font-weight: bold; font-style: italic;">foo</span>=${<span style="font-weight: bold; font-style: italic;">var</span>:+&amp;<span style="font-weight: bold; font-style: italic;">key</span>=var}
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org9aebe6f" class="outline-3">
+<h3 id="org9aebe6f"><span class="section-number-3">4.13</span> Interpolation</h3>
+<div class="outline-text-3" id="text-4-13">
+<p>
+We previously saw that functions can be passed around as strings,
+and be called later on.
+</p>
+
+<p>
+Something that might not be obvious is that the string can be
+created from shorter strings, and that allows for an extra
+flexibility, that comes with its own dangers, but it's a very
+useful pattern to dispatch functions based on user input or
+function outputs.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">l</span>=l
+<span style="font-weight: bold; font-style: italic;">s</span>=s
+$<span style="font-weight: bold; font-style: italic;">l</span>$<span style="font-weight: bold; font-style: italic;">s</span> .
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orga9ed6bc" class="outline-3">
+<h3 id="orga9ed6bc"><span class="section-number-3">4.14</span> dispatch functions using args</h3>
+<div class="outline-text-3" id="text-4-14">
+<p>
+A nice usage of the previous technique is using user input as a
+dispatching method.
+</p>
+
+<p>
+You've probably seen this pattern already:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">while</span> [[ $<span style="font-weight: bold; font-style: italic;">#</span> -gt 0 ]]; <span style="font-weight: bold;">do</span>
+
+<span style="font-weight: bold;">case</span> $<span style="font-weight: bold; font-style: italic;">1</span><span style="font-weight: bold;"> in</span>
+  foo)
+    foo
+    ;;
+  *)
+    <span style="font-weight: bold;">exit</span> 1
+    ;;
+<span style="font-weight: bold;">esac</span>
+<span style="font-weight: bold;">shift</span>
+<span style="font-weight: bold;">done</span>
+</pre>
+</div>
+
+<p>
+And it is useful for its own good, and flexible.
+</p>
+
+<p>
+But for some simpler cases, we can dispatch based on the variable
+itself:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">cmd_foo</span>() {
+ do-something
+}
+
+cmd_$<span style="font-weight: bold; font-style: italic;">1</span>
+</pre>
+</div>
+
+<p>
+The problem with this is that in case we supply a <code>$1</code> that doesn't
+map to any <code>cmd_$1</code> we'll get something like
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">bash: cmd_notexisting: command not found
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orgb7858eb" class="outline-3">
+<h3 id="orgb7858eb"><span class="section-number-3">4.15</span> command_not_found_handle</h3>
+<div class="outline-text-3" id="text-4-15">
+<p>
+Here's a detail on a kinda obscure bash (only bash) feature.
+</p>
+
+<p>
+You can set a hook that will be called when bash tries to run a
+command and it doesn't find it.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">command_not_found_handle</span>() {
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$1 is not a correct command. Cmds allowed:"</span>
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$(typeset -F | grep cmd_ | sed -e 's/.*cmd_/cmd_/')"</span>
+}
+
+<span style="font-weight: bold;">cmd_foo</span>() {
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"foo"</span>
+}
+
+<span style="font-weight: bold;">cmd_baz</span>() {
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"baz"</span>
+}
+cmd_bar
+</pre>
+</div>
+
+<p>
+You can unset the function <code>command_not_found_handle</code> to go back to
+the normal behavior.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgb5e6212" class="outline-3">
+<h3 id="orgb5e6212"><span class="section-number-3">4.16</span> Return Values for Conditionals</h3>
+<div class="outline-text-3" id="text-4-16">
+<p>
+<code>if</code> 's test condition can use the return values of
+commands. That's a known thing, but a lot of code you see around
+relies on <code>[[]]</code> to test the return values of commands/functions
+anyway.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">if </span><span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"foo"</span> | grep <span style="font-style: italic;">"bar"</span> ; <span style="font-weight: bold;">then</span>
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"found!"</span>
+<span style="font-weight: bold;">fi</span>
+</pre>
+</div>
+
+<p>
+This is much clearer than
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">if</span> [[ ! -z $( <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"foo"</span> | grep <span style="font-style: italic;">"bar"</span>) ]]; <span style="font-weight: bold;">then</span>
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"found!"</span>
+<span style="font-weight: bold;">fi</span>
+</pre>
+</div>
+
+<p>
+As easy and trivial as it seems, this way of thinking pushes you
+forward to thinking about creating smaller functions that check the
+conditions and <code>return</code> 0 or non 0. It's syntactically smaller, and
+usually makes you play by the rules of the commands, more than just
+finding your way around the output strings.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">if</span> less_than $<span style="font-weight: bold; font-style: italic;">package</span> <span style="font-style: italic;">"1.3.2"</span>; <span style="font-weight: bold;">then</span>
+  die <span style="font-style: italic;">"can't proceed"</span>
+<span style="font-weight: bold;">fi</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org54df9a7" class="outline-3">
+<h3 id="org54df9a7"><span class="section-number-3">4.17</span> set variable in an "if" test</h3>
+<div class="outline-text-3" id="text-4-17">
+<p>
+Usual pattern to capture the output of a command and branch
+depending on its return value is:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">res</span>=<span style="font-style: italic;">"$(... whatever ...)"</span>
+<span style="font-weight: bold;">if</span> [ <span style="font-style: italic;">"$?"</span> -eq 0 ]; <span style="font-weight: bold;">then</span> ...
+                        ...
+<span style="font-weight: bold;">fi</span>
+</pre>
+</div>
+
+<p>
+Well, you can test the return value AND capture the output at the
+same time!
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">if</span> <span style="font-weight: bold; font-style: italic;">res</span>=<span style="font-style: italic;">"$(...)"</span>; <span style="font-weight: bold;">then</span>
+  ...
+<span style="font-weight: bold;">fi</span>
+</pre>
+</div>
+
+<p>
+Unfortunately, it doesnt' work with <code>local</code>, so you can't be
+defining a local var in the same line. So, the variable is either
+global, or you spent a line to declare it local before. Still, I
+think I prefer to have a line to declare the variable as local
+rather than having explicit <code>$?</code>'s around.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">local var1
+<span style="font-weight: bold;">if</span> <span style="font-weight: bold; font-style: italic;">var1</span>=$(f); <span style="font-weight: bold;">then</span>
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$var1"</span>
+<span style="font-weight: bold;">fi</span>
+</pre>
+</div>
+<p>
+Ref: <a href="https://news.ycombinator.com/item?id=27163494">https://news.ycombinator.com/item?id=27163494</a>
+</p>
+</div>
+</div>
+
+<div id="outline-container-org2b61f9c" class="outline-3">
+<h3 id="org2b61f9c"><span class="section-number-3">4.18</span> Do work on loop conditions</h3>
+<div class="outline-text-3" id="text-4-18">
+<p>
+I've not seen it used a lot (and there might be a reason for it,
+who knows), <code>while</code> conditions are just plain commands, so you can
+put other stuff than <code>[]/[[]]/test</code> there.
+</p>
+
+<p>
+Heres's an idiomatic way to iterate through all the arguments of a
+function while consuming the <code>$*</code> array.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">while</span>(($<span style="font-weight: bold; font-style: italic;">#</span>)) ; <span style="font-weight: bold;">do</span>
+  <span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">...</span>
+  <span style="font-weight: bold;">shift</span>
+<span style="font-weight: bold;">done</span>
+</pre>
+</div>
+
+<p>
+And here's a pseudo-repl that keeps shooting one-off commands. This
+will keep shooting <code>tr</code> commands to whatever strings you give it,
+with the usual rlwrap goodies.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">while</span> rlwrap -o -S<span style="font-style: italic;">'&gt;&gt; '</span> tr a-z A-Z ; <span style="font-weight: bold;">do</span> :; <span style="font-weight: bold;">done</span>
+</pre>
+</div>
+
+<p>
+Note: <code>:</code> is a nop builtin in bash.
+</p>
+</div>
+</div>
+<div id="outline-container-org18dee81" class="outline-3">
+<h3 id="org18dee81"><span class="section-number-3">4.19</span> One Branch Conditionals</h3>
+<div class="outline-text-3" id="text-4-19">
+<p>
+The usual conditionals one sees everywhere look like <code>if</code>.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">if</span> [[ some-condition ]]; <span style="font-weight: bold;">then</span>
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"yes"</span>
+<span style="font-weight: bold;">fi</span>
+</pre>
+</div>
+
+<p>
+This is all good and fine, but in the same vein of using the least
+powerful construct for each task, it's nice to think of the one way
+conditionals in the form of <code>&amp;&amp;</code> and <code>||</code> as a way to explicitly
+say that we don't want to do anything else when the condition is
+not met. It's a hint to the reader.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">some-condition || {
+   <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"log: warning!"</span>
+}
+
+other-condition &amp;&amp; {
+   <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"log: all cool"</span>
+}
+</pre>
+</div>
+
+<p>
+This conveys the intention of doing something <b>just</b> in one case,
+and that the negation of this is not interesting at all. There's a
+big warning you have to be aware of. The same as with lua's
+<code>... and .. or ..</code>, bash <code>||</code> and <code>&amp;&amp;</code> are not interchangeable for
+<code>if...else...end</code>. <a href="https://mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3">BashWiki</a> has an explanation why, but, the same
+as in Lua's case, if the "then" part returns false, the else will
+run.
+</p>
+
+<p>
+There are lots of references to this, but I like this recent post
+where it explains it for arrays in higher level languages like ruby:
+<a href="https://jesseduffield.com/array-functions-and-the-rule-of-least-power/">https://jesseduffield.com/array-functions-and-the-rule-of-least-power/</a>
+</p>
+
+<p>
+An extended article of this kind of conditionals can be found <a href="https://timvisee.com/blog/elegant-bash-conditionals/">here</a>.
+</p>
+</div>
+</div>
+<div id="outline-container-orgfbef4b5" class="outline-3">
+<h3 id="orgfbef4b5"><span class="section-number-3">4.20</span> pushd/popd</h3>
+<div class="outline-text-3" id="text-4-20">
+<p>
+pushd and popd are used to move to some directory and go back to it
+in a stack fashion, so nesting can happen and you never lose
+track. The problem is that it still is on you to have a <code>popd</code> per
+<code>pushd</code>.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">pushd /tmp/my-dir
+  <span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">PWD</span>
+popd
+</pre>
+</div>
+
+<p>
+Here's an alternative way, that at least makes sure that you close
+all pushd with a popd.
+</p>
+
+<p>
+Starting a new shell and cd-ing , will make all commands in that
+subshell be in that directory, and will come back to the old
+directory after closing the new spawned shell.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">(<span style="font-weight: bold;">cd</span> /tmp/my-dir
+  ls
+)
+</pre>
+</div>
+
+<p>
+Remember to <code>inherit_errexit</code> or <code>set -e</code> inside the subshell if
+you need. That's a very easy trap to fall into.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org7423475" class="outline-3">
+<h3 id="org7423475"><span class="section-number-3">4.21</span> wrap functions</h3>
+<div class="outline-text-3" id="text-4-21">
+<p>
+Bash can't pass blocks of code around, but the alternative is to
+pass functions.  More on that later.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">mute</span>() {
+  <span style="font-style: italic;">"$@"</span> &gt;/dev/null
+}
+
+mute pushd /tmp/foobar
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-org7ef1223" class="outline-3">
+<h3 id="org7ef1223"><span class="section-number-3">4.22</span> use [[</h3>
+<div class="outline-text-3" id="text-4-22">
+<p>
+Unless you want your script to be POSIX compliant, use <code>[[</code> instead
+of <code>[</code>.  <code>[</code> is a regular command. It's like <code>ls</code>, or <code>true</code>. You can
+check it by searching for a file named <code>[</code> in your path.
+</p>
+
+<p>
+Being a normal command it always evaluates its params, like a
+regular function. On the other hand though, <code>[[</code> is a special bash
+operator, and it evaluates the parameters lazily.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">[[ does lazy evaluation:</span>
+[[ a = b &amp;&amp; $(<span style="font-weight: bold;">echo</span> foo &gt;&amp;2) ]]
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">[ does not:</span>
+[ a = b -a <span style="font-style: italic;">"$(echo foo &gt;&amp;2)&#8221; ]</span>
+</pre>
+</div>
+<p>
+Ref: <a href="https://lists.gnu.org/archive/html/help-bash/2014-06/msg00013.html">https://lists.gnu.org/archive/html/help-bash/2014-06/msg00013.html</a>
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgee706c0" class="outline-3">
+<h3 id="orgee706c0"><span class="section-number-3">4.23</span> eval?</h3>
+<div class="outline-text-3" id="text-4-23">
+<p>
+When you have mostly small functions that are mostly pure, you
+compose them like you'd do in any other language.
+</p>
+
+<p>
+In the following snippet, we are in a release script. Some step
+builds a package inside a docker container, another step tests a
+package already built.
+</p>
+
+<p>
+A nice way to build ubuntus, for example, is to add an ARG to the
+Dockerfile so we can build several ubuntu versions using the same
+file.
+</p>
+
+<p>
+It'd look like this:
+</p>
+<div class="org-src-container">
+<pre class="src src-Dockerfile">ARG VERSION
+FROM ubuntu:$VERSION
+
+RUN apt-get ...
+...
+</pre>
+</div>
+
+<p>
+We build that image and do all the building inside it, mounting a
+volume shared with our host, so we can extract our <code>.deb</code> file
+easily.
+</p>
+
+<p>
+After that, to do some smoke tests on the package, the idea is to
+install the <code>.deb</code> file in a fresh ubuntu image.
+</p>
+
+<p>
+Let's pick the same base image we picked to build the package.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">evaluate the string "centos:$VERSION" (that comes from</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">centos/Dockerfile) in the current scope</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">DISTRO is ubuntu:18.04</span>
+local <span style="font-weight: bold; font-style: italic;">VERSION</span>=$(get_version $<span style="font-weight: bold; font-style: italic;">DISTRO</span>) <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">VERSION==18.04</span>
+run_test <span style="font-style: italic;">"file.deb"</span> <span style="font-style: italic;">"$(eval echo $(awk '/^FROM /{print $2; exit}' $LOCAL_PATH/$(get_dockerfile_for $DISTRO)))"</span> <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">ubuntu:18.04</span>
+</pre>
+</div>
+
+<p>
+The usage of eval is there to interpolate the string that we get
+from the <code>FROM</code> in the current environment.
+</p>
+
+<p>
+WARNING: You know, anything that uses <code>eval</code> is dangerous per
+se. Do not use it unless you know very well what you're doing AND
+the input is 100% under your control. Usually, more restricted
+commands can achieve what you want to do. In this particular case,
+you could use <code>envsubst</code>, or just manually replace <code>$\{?VERSION\}?</code>
+in a sed.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">test_release <span style="font-style: italic;">"$PACKAGE_PATH"</span> $(awk <span style="font-style: italic;">'/^FROM /{print $2; exit}'</span> $<span style="font-weight: bold; font-style: italic;">LOCAL_PATH</span>/$(get_dockerfile_for $<span style="font-weight: bold; font-style: italic;">DISTRO</span>) | sed -e <span style="font-style: italic;">"s/\$VERSION/$VERSION/"</span>)
+</pre>
+</div>
+
+<p>
+Yet another way is using <a href="https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html">shell parameter expansions.</a>
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">
+<span style="font-weight: bold; font-style: italic;">var1</span>=value
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'this is $var1'</span> &gt;/tmp/f.txt
+<span style="font-weight: bold; font-style: italic;">f</span>=$(cat /tmp/f.txt)
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"${f}"</span>  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">this is $var1</span>
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"${f@P}"</span>  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">this is value</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org02c12cf" class="outline-3">
+<h3 id="org02c12cf"><span class="section-number-3">4.24</span> pass commands around</h3>
+<div class="outline-text-3" id="text-4-24">
+<p>
+This one uses <a href="#orgb9cc112">DRY_RUN</a>. While refactoring a script that does some
+curls, we want to make sure that our refactored version does the
+exact same calls in the same order.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">compare_outputs</span>() {
+  <span style="font-weight: bold;">export</span> <span style="font-weight: bold; font-style: italic;">DRY_RUN</span>=1
+  git checkout b1
+  $<span style="font-weight: bold; font-style: italic;">@</span> 2&gt;/tmp/1.out
+  git checkout b2
+  $<span style="font-weight: bold; font-style: italic;">@</span> 2&gt;/tmp/2.out
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"diffing"</span>
+  diff /tmp/1.out /tmp/2.out
+}
+compare_outputs ./release.sh -p rhel:6 -R <span style="font-style: italic;">'internal-preview'</span>
+</pre>
+</div>
+
+<p>
+First we create a function <code>compare_outputs</code>, that gets a command
+to run as parameters. The function will run it once, redirecting
+the standard error to a file <code>/tmp/1.out</code>.
+</p>
+
+<p>
+Then, it checks out the branch that contains our refactored
+version, and will run the command again, redirecting standard error
+to <code>/tmp/2.out</code>, and will diff the two outputs.
+</p>
+
+<p>
+In case there's a difference between the two, <code>diff</code> will output
+them, and the function will return the non-zero exit value of
+diff. If everything went fine, <code>compare_outputs</code> will succeed.
+</p>
+
+<p>
+Now that we know that for these inputs the command runs fine, we
+want to find out if it works for other types of releases, not only
+internal-preview.
+</p>
+
+<p>
+Here I'm using zsh's global aliases to give a much more fluid
+interface to the commands, but you can use the regular while/for
+loops:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-shell">alias -g <span style="font-weight: bold; font-style: italic;">SPLIT</span>=<span style="font-style: italic;">'| tr " " "\n" '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">FORI</span>=<span style="font-style: italic;">'| while read i ; do '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">IROF</span>=<span style="font-style: italic;">'; done '</span>
+
+<span style="font-weight: bold;">set</span> -e
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"ga internal-preview rc1 rc2"</span> SPLIT FORI
+   noglob compare_outputs ./release.sh -p rhel:8 -R <span style="font-style: italic;">"$i"</span>
+IROF
+</pre>
+</div>
+
+<p>
+So, combining the two, we can have a really smooth way of iterating
+over the possibilities, without really messing into the details of
+loops.
+</p>
+
+<p>
+WARNING: This approach is not robust enough to put it anywhere in
+production, but to write quick one off scripts is a
+killer. Experimenting in a shell and creating tools and 2nd order
+tools to make interaction faster builds a language that grows on
+you, and keeps improving your toolbelt.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org56dd1ec" class="outline-3">
+<h3 id="org56dd1ec"><span class="section-number-3">4.25</span> The Toplevel Is Hopeless</h3>
+<div class="outline-text-3" id="text-4-25">
+<p>
+Shellscripts are thought as quick one-off programs, but when they
+are useful, they are sticky, so you better write them from the
+start as if it would be permanent. The upfront cost is very low
+anyway. Structure the script like a regular app.
+</p>
+
+<p>
+Bash is extremely permissive in what it allows to be coded and
+ran. By default, failures do not make the program exit or throw an
+exception (no exceptions). And for some reason, the common
+usage of shellscripts is to put everything in the top level. Don't
+do that. Do the least possible things in the toplevel.
+</p>
+
+<p>
+A way to improve the defaults, is setting a bunch of flags that
+make the script stricter, so it fails on many situations you'd
+want to stop anyway because something went wrong.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">!/usr/bin/</span><span style="font-weight: bold;">env</span><span style="font-weight: bold; font-style: italic;"> bash</span>
+<span style="font-weight: bold;">set</span> -eEuo pipefail
+shopt -s inherit_errexit
+
+<span style="font-weight: bold;">main</span>() {
+  parse_args
+  validate_args
+  do_things
+  cleanup
+}
+
+main <span style="font-style: italic;">"$@"</span>
+</pre>
+</div>
+
+<p>
+Ref: <a href="https://dougrichardson.us/2018/08/03/fail-fast-bash-scripting.html">https://dougrichardson.us/2018/08/03/fail-fast-bash-scripting.html</a>
+</p>
+
+<p>
+Although&#x2026; <a href="http://mywiki.wooledge.org/BashFAQ/105">Why doesn't set -e do what I expected?</a>
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgf392454" class="outline-3">
+<h3 id="orgf392454"><span class="section-number-3">4.26</span> Check your deps</h3>
+<div class="outline-text-3" id="text-4-26">
+<p>
+Giving useful information to the users will help them using the
+script, and you debugging it. Script dependencies is a common use
+case that we'll do it in a nice way.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">deps</span>() {
+  <span style="font-weight: bold;">for</span> dep<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"$@"</span>; <span style="font-weight: bold;">do</span>
+    mute command -v <span style="font-style: italic;">"$dep"</span> || die <span style="font-style: italic;">"$dep dependency missing"</span>
+  <span style="font-weight: bold;">done</span>
+}
+
+<span style="font-weight: bold;">main</span>() {
+  deps jq curl
+  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">...</span>
+}
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org3ffffeb" class="outline-3">
+<h3 id="org3ffffeb"><span class="section-number-3">4.27</span> source files</h3>
+<div class="outline-text-3" id="text-4-27">
+<p>
+<code>source</code> is like <code>require</code> or <code>import</code> in some programming
+languages. It evaluates the sourced file in the context of the
+current script, so you get all definitions in your environment.
+</p>
+
+<p>
+It's simple, but it helps you get used to modularize your code into
+libraries.
+</p>
+
+<p>
+Be careful, it's very rudimentary, and it will be overwriting old
+vars or functions if names clash. There's no namespacing happening
+there.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">source file.sh
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">the same</span>
+. file.sh
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orgb88dd1f" class="outline-3">
+<h3 id="orgb88dd1f"><span class="section-number-3">4.28</span> Use Scripts as a Libs</h3>
+<div class="outline-text-3" id="text-4-28">
+<p>
+A python-inspired way of using scripts as loadable libraries is to
+check whether the current file was the one that was called
+originally or it's being just sourced.
+</p>
+
+<p>
+Again, no side effects in load time makes this functionality
+possible. otherwise, you're on your own.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">Allow sourcing of this script</span>
+<span style="font-weight: bold;">if</span> [[ $(basename <span style="font-style: italic;">"$(realpath "$0")"</span>) == <span style="font-style: italic;">"$(basename "${BASH_SOURCE}")"</span> ]]; <span style="font-weight: bold;">then</span>
+  setup
+  parse_args <span style="font-style: italic;">"$@"</span>
+  main
+<span style="font-weight: bold;">fi</span>
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-orgde4ff58" class="outline-3">
+<h3 id="orgde4ff58"><span class="section-number-3">4.29</span> Tmpfiles Everywhere</h3>
+<div class="outline-text-3" id="text-4-29">
+<p>
+Your script is not going to run alone. Don't assume paths are
+fixed or known.
+</p>
+
+<p>
+CI/CD Pipelines run many jobs in the same node and files can start
+clashing.
+</p>
+
+<p>
+Make use of <code>$(mktemp -d /tmp/foo-bar.XXXXX)</code>.  If you have to patch a
+file, do it in a clean fresh copy. Don't modify files in old paths
+</p>
+
+<p>
+If you HAVE TO modify paths, do it idempotently.  But really, don't do it.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">git_clone_tmp</span>() {
+  local <span style="font-weight: bold; font-style: italic;">repo</span>=${<span style="font-weight: bold; font-style: italic;">1</span>:?repo is required}
+  local <span style="font-weight: bold; font-style: italic;">ref</span>=${<span style="font-weight: bold; font-style: italic;">2</span>:?ref is required}
+  <span style="font-weight: bold; font-style: italic;">tmpath</span>=$(mktemp -d <span style="font-style: italic;">"/tmp/cloned-$repo-XXXXX"</span>)
+  on_exit <span style="font-style: italic;">"rm -rf $tmpath"</span>
+  git clone -b ${<span style="font-weight: bold; font-style: italic;">ref</span>} $<span style="font-weight: bold; font-style: italic;">repo</span> $<span style="font-weight: bold; font-style: italic;">tmpath</span>
+}
+</pre>
+</div>
+
+<p>
+CAVEAT: You have to manually delete the directory if you want it cleaned.
+</p>
+
+<p>
+Here's an article with very good advice on <a href="https://www.netmeister.org/blog/mktemp.html">tempfiles</a>.
+</p>
+</div>
+</div>
+<div id="outline-container-orgbb023dc" class="outline-3">
+<h3 id="orgbb023dc"><span class="section-number-3">4.30</span> Cleanup tasks with trap</h3>
+<div class="outline-text-3" id="text-4-30">
+<p>
+<code>trap</code> is used to 'subscribe' a callback when something happens.
+Many times it's used on exit. It's a good thing to cleanup tmpdirs after your script
+exits, so you can use the output of <code>mktemp -d</code> and subscribe a cleanup
+function for it.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">on_exit</span>() {
+  rm -rf $<span style="font-weight: bold; font-style: italic;">1</span>
+}
+local <span style="font-weight: bold; font-style: italic;">tmpath</span>=$(mktemp -d /tmp/foo-bar.XXXXX)
+<span style="font-weight: bold;">trap</span> <span style="font-style: italic;">"on_exit $tmpath"</span> EXIT SIGINT
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org36bb32c" class="outline-3">
+<h3 id="org36bb32c"><span class="section-number-3">4.31</span> array of callbacks on_exit</h3>
+<div class="outline-text-3" id="text-4-31">
+<p>
+Level up that pattern, we can have a helper to add callbacks to run
+on exit. Get used to these kind of patterns, they are super
+powerful and save you lots of manual bookkeeping.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">
+<span style="font-weight: bold; font-style: italic;">ON_EXIT</span>=()
+<span style="font-weight: bold; font-style: italic;">EXIT_RES</span>=
+
+<span style="font-weight: bold;">function</span> <span style="font-weight: bold;">on_exit_fn</span> {
+  <span style="font-weight: bold; font-style: italic;">EXIT_RES</span>=$<span style="font-weight: bold; font-style: italic;">?</span>
+  <span style="font-weight: bold;">for</span> cb<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"${ON_EXIT[@]}"</span>; <span style="font-weight: bold;">do</span> $<span style="font-weight: bold; font-style: italic;">cb</span> || true; <span style="font-weight: bold;">done</span>
+  <span style="font-weight: bold;">return</span> $<span style="font-weight: bold; font-style: italic;">EXIT_RES</span>
+}
+
+<span style="font-weight: bold;">trap</span> on_exit_fn EXIT SIGINT
+
+<span style="font-weight: bold;">function</span> <span style="font-weight: bold;">on_exit</span> {
+  ON_EXIT+=(<span style="font-style: italic;">"$@"</span>)
+}
+
+local <span style="font-weight: bold; font-style: italic;">v_id</span>=$(docker volume create)
+on_exit <span style="font-style: italic;">"docker volume rm $v_id"</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">Use your v_id knowing that it'll be available during your script but</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">will be cleaned up before exiting.</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org2fe2244" class="outline-3">
+<h3 id="org2fe2244"><span class="section-number-3">4.32</span> stacktrace on error</h3>
+<div class="outline-text-3" id="text-4-32">
+<p>
+Here's a nice helper for debugging errors in bash. In case of non-0
+exit, it prints a stacktrace.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">set</span> -Eeuo pipefail
+<span style="font-weight: bold;">trap</span> stacktrace EXIT
+<span style="font-weight: bold;">stacktrace</span>() {
+    <span style="font-weight: bold; font-style: italic;">rc</span>=<span style="font-style: italic;">"$?"</span>
+    <span style="font-weight: bold;">if</span> [ $<span style="font-weight: bold; font-style: italic;">rc</span> != 0 ]; <span style="font-weight: bold;">then</span>
+        printf <span style="font-style: italic;">'\nThe command "%s" triggerd a stacktrace:\n'</span> <span style="font-style: italic;">"$BASH_COMMAND"</span>
+        <span style="font-weight: bold;">for</span> i<span style="font-weight: bold;"> in</span> $(seq 1 $((${#<span style="font-weight: bold; font-style: italic;">FUNCNAME</span>[@]} - 2))); <span style="font-weight: bold;">do</span>
+          <span style="font-weight: bold; font-style: italic;">j</span>=$((i+1));
+          printf <span style="font-style: italic;">'\t%s: %s() called in %s:%s\n'</span> <span style="font-style: italic;">"${BASH_SOURCE[$i]}"</span> <span style="font-style: italic;">"${FUNCNAME[$i]}"</span> <span style="font-style: italic;">"${BASH_SOURCE[$j]}"</span> <span style="font-style: italic;">"${BASH_LINENO[$i]}"</span>;
+        <span style="font-weight: bold;">done</span>
+    <span style="font-weight: bold;">fi</span>
+}
+
+</pre>
+</div>
+<p>
+ref: <a href="https://news.ycombinator.com/item?id=26644110">https://news.ycombinator.com/item?id=26644110</a>
+</p>
+</div>
+</div>
+<div id="outline-container-org42e5305" class="outline-3">
+<h3 id="org42e5305"><span class="section-number-3">4.33</span> Dots and colons allowed in function names!</h3>
+<div class="outline-text-3" id="text-4-33">
+<p>
+A way to split the namespace is to have libs define functions with
+their own namespace.
+</p>
+
+<p>
+I've gotten used to use dots or colons as namespace separator.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">semver.greater</span>() {
+ <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">...</span>
+}
+</pre>
+</div>
+<p>
+or
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">semver:greater() {
+ <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">...</span>
+}
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-org212b4c0" class="outline-3">
+<h3 id="org212b4c0"><span class="section-number-3">4.34</span> make steps of the process as composable as possible by using "$@"</h3>
+<div class="outline-text-3" id="text-4-34">
+<p>
+By using <code>$@</code> to pass commands as parameters around you can get to
+a degree of composability that allows for a nice chaining of
+commands.
+</p>
+
+<p>
+Here's a very simple version of <code>watch</code>. See how you can <code>every 2
+   ls -la</code>. I think that style is called Bernstein Chaining. But I'm
+not sure if it's exactly the same. It also looks like currying or
+partial evaluation to me if you squint a little bit.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">every</span>() {
+   <span style="font-weight: bold; font-style: italic;">secs</span>=$<span style="font-weight: bold; font-style: italic;">1</span>
+   <span style="font-weight: bold;">shift</span>
+   <span style="font-weight: bold;">while</span> true; <span style="font-weight: bold;">do</span>
+     <span style="font-style: italic;">"$@"</span>
+     sleep $<span style="font-weight: bold; font-style: italic;">secs</span>;
+   <span style="font-weight: bold;">done</span>
+ }
+</pre>
+</div>
+
+
+<p>
+As you know by now, bash doesn't pass blocks of code around, but
+the alternative is to pass function names.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">mute</span>() {
+  $<span style="font-weight: bold; font-style: italic;">@</span> &gt;/dev/null 2&gt;/dev/null
+}
+mute ls
+</pre>
+</div>
+
+<p>
+So now we can create the most useless command composition ever:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">every 1 mute echo hi
+<span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">or</span>
+mute every 1 echo hi
+</pre>
+</div>
+
+<p>
+For the particular redirection problem, another option is to use
+aliases. Redirects can be written anywhere on your CLI (not just at
+the end), so the following will work using a plain alias:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">alias <span style="font-weight: bold; font-style: italic;">mute</span>=<span style="font-style: italic;">'&gt;/dev/null 2&gt;/dev/null'</span>
+mute ls
+</pre>
+</div>
+
+
+
+<ul class="org-ul">
+<li><a href="https://www.oilshell.org/blog/2017/01/13.html">https://www.oilshell.org/blog/2017/01/13.html</a></li>
+</ul>
+</div>
+</div>
+<div id="outline-container-orgb37df27" class="outline-3">
+<h3 id="orgb37df27"><span class="section-number-3">4.35</span> do_times/foreach_*</h3>
+<div class="outline-text-3" id="text-4-35">
+<p>
+shellscripts are highly side-efffecty, and even though the scoping
+of variables is not very empowering, you can get a limited amount
+of decomposition of loops by passing function names.
+</p>
+
+<p>
+This is a lame example, but I hope it shows the use case, it allows
+you to group already existing functions while taking advantage of a
+fixed looping iterator, and leaving traces of the current loop vars
+in the global "variable" environment.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">create_user</span>() {
+  <span style="font-weight: bold; font-style: italic;">uname</span>=<span style="font-style: italic;">"u$1"</span> <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">leave uname in the global env so later functions see it</span>
+  http :8080/users <span style="font-weight: bold; font-style: italic;">name</span>=<span style="font-style: italic;">"$uname"</span>
+}
+
+<span style="font-weight: bold;">create_pet</span>() {
+  <span style="font-weight: bold; font-style: italic;">pname</span>=<span style="font-style: italic;">"p$1"</span>
+  http :8080/users/$<span style="font-weight: bold; font-style: italic;">uname</span>/pets <span style="font-weight: bold; font-style: italic;">name</span>=<span style="font-style: italic;">"$pname"</span>
+}
+
+<span style="font-weight: bold;">create_bundle</span>() {
+  create_user $<span style="font-weight: bold; font-style: italic;">1</span>
+  create_pet $<span style="font-weight: bold; font-style: italic;">1</span>
+}
+
+<span style="font-weight: bold;">do_times</span>() {
+  local <span style="font-weight: bold; font-style: italic;">n</span>=$<span style="font-weight: bold; font-style: italic;">1</span>; <span style="font-weight: bold;">shift</span>
+  <span style="font-weight: bold;">for</span> i<span style="font-weight: bold;"> in</span> $(seq $<span style="font-weight: bold; font-style: italic;">n</span>); <span style="font-weight: bold;">do</span>
+    <span style="font-style: italic;">"$@"</span> $<span style="font-weight: bold; font-style: italic;">i</span>
+  <span style="font-weight: bold;">done</span>
+}
+
+do_times 15 create_bundle
+</pre>
+</div>
+
+<p>
+A bit more complex is runnning a command to every repo in an org:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">run_tests</span>() {
+  ./ci/test.sh
+}
+
+<span style="font-weight: bold;">foreach_repo_with_index</span>() {
+  local <span style="font-weight: bold; font-style: italic;">counter</span>=0
+  local <span style="font-weight: bold; font-style: italic;">repos</span>=$(http https://api.github.com/users/$<span style="font-weight: bold; font-style: italic;">1</span>/repos)
+  <span style="font-weight: bold;">shift</span>
+  <span style="font-weight: bold;">for</span> entry<span style="font-weight: bold;"> in</span> $(<span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">repos</span> | jq -r <span style="font-style: italic;">'.[].git_url'</span>); <span style="font-weight: bold;">do</span>
+    (git_clone_tmp $<span style="font-weight: bold; font-style: italic;">entry</span> master
+     <span style="font-weight: bold;">cd</span> $<span style="font-weight: bold; font-style: italic;">tmpath</span>
+     <span style="font-style: italic;">"$@"</span> $<span style="font-weight: bold; font-style: italic;">counter</span> $<span style="font-weight: bold; font-style: italic;">entry</span>
+    )
+    ((<span style="font-weight: bold; font-style: italic;">counter</span>=counter+1))
+  <span style="font-weight: bold;">done</span>
+}
+
+foreach_repo_with_index kidd run_tests
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orgdafc152" class="outline-3">
+<h3 id="orgdafc152"><span class="section-number-3">4.36</span> &lt;(foo) and &gt;(foo)</h3>
+<div class="outline-text-3" id="text-4-36">
+<p>
+Some commands ask for files as inputs. And sometimes you have that
+file, but sometimes you're only creating that file to pass it to
+the command.  In those cases, creating temporary files is not
+necessary if you use <code>&lt;(cmd)</code>. Here's a way to diff the output of 2
+commands without putting them in a temporary file.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">diff &lt;(date) &lt;(date)
+diff &lt;(date) &lt;(sleep 1; date)
+</pre>
+</div>
+
+<p>
+The same happens with outputs. Commands that ask you for a
+destination file. You can trick them by using <code>&gt;(command)</code> as a
+file. A nice trick is to use <code>&gt;(cat)</code> to know what's going on
+there. Also useful to send stuff to the clipboard <code>&gt;(xclip)</code> before
+running something on the output.
+</p>
+
+<p>
+What the shell does in those cases is to bind a file descriptor of
+the process created inside <code>&lt; or &gt;</code> to the first process.
+</p>
+
+<p>
+You can experiment with those using commands like <code>echo &lt;(pwd)</code>.
+</p>
+
+<p>
+In Zsh you can use <code>m-x expand-word</code> to see the file descriptors
+being expanded.
+</p>
+
+<p>
+A way to peek into a huge pipe is to <code>tee &gt;(cat)</code>
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgb79e87a" class="outline-3">
+<h3 id="orgb79e87a"><span class="section-number-3">4.37</span> Modify behavior by linking files</h3>
+<div class="outline-text-3" id="text-4-37">
+<p>
+Imagine you want to remove the <code>.bash_history</code> file and not record
+history of commands.  You don't can't avoid bash to write to that
+file, but what you can do is to link <code>.bash_history</code> to
+<code>/dev/null</code>. That way, bash will keep appending things to the
+expected output file, without noticing that it is really writing to
+<code>/dev/null</code>. The trick is to use: <code>ln -sf /dev/null .bash_history</code>.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgdde7c4f" class="outline-3">
+<h3 id="orgdde7c4f"><span class="section-number-3">4.38</span> Modify a file on the fly, without changing it on disk</h3>
+<div class="outline-text-3" id="text-4-38">
+<p>
+If you want to use a slightly modified version of a file for a
+single use, and then throw it away, consider the following:
+</p>
+
+<p>
+Everywhere that you should pass <code>file</code>, you could pass <code>&lt;(cat
+   orig_file)</code> instead, because they have the same content, only the
+second version is ephemeral.
+</p>
+
+<p>
+If you want a modified version of it, we can attach more commands
+to the subshell.
+</p>
+
+<p>
+Example of a command that reuses your <code>~/.psqlrc</code> and adds a line
+in the end to make the session read-only.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">ropsql</span>() {
+  <span style="font-weight: bold; font-style: italic;">PSQLRC</span>=&lt;(
+    cat ~/.psqlrc &amp;&amp;
+    <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'set session characteristics as transaction read only;'</span>) <span style="font-style: italic;">\</span>
+  psql <span style="font-style: italic;">"$@"</span>
+}
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orgd157786" class="outline-3">
+<h3 id="orgd157786"><span class="section-number-3">4.39</span> Use xargs</h3>
+<div class="outline-text-3" id="text-4-39">
+<p>
+Continuing with other ways of plumbing commands into other
+commands, there's <code>xargs</code>. Some commands work seamlessly with
+pipes, by taking inputs from stdin and printing to stdout.  But
+some others like to work with files, and they ask for their
+parameters in their args list. For example, <code>evince</code>. It wouldn't
+be even expected to cat a pdf and pass it to evince through
+stdin.
+</p>
+
+<p>
+In general, to convert from this pattern: <code>cmd param</code> to <code>echo
+   param| cmd</code>, xargs can be helpful. Look at its man page to know how
+to split or batch args in multiple <code>cmd</code> calls.
+</p>
+
+<p>
+Xargs is helpful for parallelizing work. You should look at its man
+page, but just know it can help in running parallel processes
+(check <code>-P</code> in its man).
+</p>
+
+<p>
+Other tips on this great <a href="https://www.oilshell.org/blog/2021/08/xargs.html">Guide to xargs</a>.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgbf1f66b" class="outline-3">
+<h3 id="orgbf1f66b"><span class="section-number-3">4.40</span> xargs + paste</h3>
+<div class="outline-text-3" id="text-4-40">
+<p>
+<code>paste</code> can be thougth as <code>zip</code>, interleaving the outputs of
+several commands line by line.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">paste &lt;(./cmd1) &lt;(./cmd2) | xargs -L1 ./cmd3
+</pre>
+</div>
+
+<p>
+Ref: <a href="https://news.ycombinator.com/item?id=29845232">https://news.ycombinator.com/item?id=29845232</a>
+</p>
+</div>
+</div>
+
+<div id="outline-container-org58f56ac" class="outline-3">
+<h3 id="org58f56ac"><span class="section-number-3">4.41</span> paste?</h3>
+<div class="outline-text-3" id="text-4-41">
+<p>
+We just saw a use of <code>paste</code>. But this command can do all sorts of
+crazy stuff joining lines.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">paste - - -d, &lt; file   <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">joins every 2 lines with comma</span>
+paste - - - -d, &lt; file   <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">joins every 3 lines with comma</span>
+paste -s -d<span style="font-style: italic;">",\n"</span> file  <span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">joins 1 and 2 lines with comma, 2 and 3 with \n</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org132da2c" class="outline-3">
+<h3 id="org132da2c"><span class="section-number-3">4.42</span> Scripts as filters</h3>
+<div class="outline-text-3" id="text-4-42">
+<p>
+Strive to create scripts that can be used as filters. Perl had
+<code>while(&lt;&gt;) { ... }</code> that would open a file line by line, or get
+input from stdin depending on the actual arguments to the file.
+</p>
+
+<p>
+In shellscripting, we can simulate (part of) it using
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">while</span> <span style="font-weight: bold; font-style: italic;">IFS</span>= read -r line
+<span style="font-weight: bold;">do</span>
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$line"</span>
+<span style="font-weight: bold;">done</span> &lt; <span style="font-style: italic;">"${1:-/dev/stdin}"</span>
+</pre>
+</div>
+
+<p>
+Look <a href="https://stackoverflow.com/questions/6980090/how-to-read-from-a-file-or-standard-input-in-bash">here</a> for more detailed explanations and variants.
+</p>
+
+<p>
+Another way to create filters is to use `"${@:-cat}"`.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">o2e</span>     () { 1&gt;&amp;2 <span style="font-style: italic;">"${@:-cat}"</span>; } <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">out to err</span>
+<span style="font-weight: bold;">e2o</span>     () { 2&gt;&amp;1 <span style="font-style: italic;">"${@:-cat}"</span>; } <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">err to out</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org7c440a6" class="outline-3">
+<h3 id="org7c440a6"><span class="section-number-3">4.43</span> Read or print to stdin inside a pipe</h3>
+<div class="outline-text-3" id="text-4-43">
+<p>
+You can use /dev/tty to explicitly specify that some input or
+output has to come from tty (being screen or keyboard).
+</p>
+
+<p>
+This is useful for code that might be called inside a pipeline,
+but you never want the contents of the pipe to be the ones that
+are <code>read</code> or <code>echoed</code>.
+</p>
+
+<p>
+Here's a snippet that defines a function fzf (if fzf is not
+previously defined), that will naively replace fzf.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">fzf is either fzf or a naive version of it</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">the input is a sed line number, so it can be</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">single number: 42</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">range: 1,10</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">separate lines: 10p;50p</span>
+mute command -v fzf ||
+  fzf() {
+    local <span style="font-weight: bold; font-style: italic;">in</span>=$(cat)
+    <span style="font-weight: bold;">for</span> p<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"${@}"</span>; <span style="font-weight: bold;">do</span>
+      [ <span style="font-style: italic;">"$p"</span> = <span style="font-style: italic;">"-0"</span> ] &amp;&amp; [ <span style="font-style: italic;">"$(echo "$in" | wc -l)"</span> -eq 1 ] &amp;&amp; [ <span style="font-style: italic;">""</span>  = <span style="font-style: italic;">"$in"</span> ] &amp;&amp; <span style="font-weight: bold;">return</span> 1
+      [ <span style="font-style: italic;">"$p"</span> = <span style="font-style: italic;">"-1"</span> ] &amp;&amp; [ <span style="font-style: italic;">"$(echo "$in" | wc -l)"</span> -eq 1 ] &amp;&amp; [ <span style="font-style: italic;">""</span> != <span style="font-style: italic;">"$in"</span> ] &amp;&amp; <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$in"</span> &amp;&amp; <span style="font-weight: bold;">return</span>
+    <span style="font-weight: bold;">done</span>
+    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">https://superuser.com/questions/1748550/read-from-stdin-while-piping-to-next-command</span>
+    cat -n &lt;(<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$in"</span>) &gt;/dev/tty
+    <span style="font-weight: bold;">read</span> -n num &lt;/dev/tty
+    <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$in"</span> | sed -n <span style="font-style: italic;">"${num}p"</span>
+  }
+</pre>
+</div>
+
+<p>
+Well&#x2026; after implementing this, I discovered `select`, which allows for these kinds of flows:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">mute command -v fzf ||
+<span style="font-weight: bold;">fzf</span>() {
+  local <span style="font-weight: bold; font-style: italic;">in</span>=$(cat)
+  <span style="font-weight: bold;">for</span> p<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"${@}"</span>; <span style="font-weight: bold;">do</span>
+    [ <span style="font-style: italic;">"$p"</span> = <span style="font-style: italic;">"-0"</span> ] &amp;&amp; [ <span style="font-style: italic;">"$(echo "$in" | wc -l)"</span> -eq 1 ] &amp;&amp; [ <span style="font-style: italic;">""</span>  = <span style="font-style: italic;">"$in"</span> ] &amp;&amp; <span style="font-weight: bold;">return</span> 1
+    [ <span style="font-style: italic;">"$p"</span> = <span style="font-style: italic;">"-1"</span> ] &amp;&amp; [ <span style="font-style: italic;">"$(echo "$in" | wc -l)"</span> -eq 1 ] &amp;&amp; [ <span style="font-style: italic;">""</span> != <span style="font-style: italic;">"$in"</span> ] &amp;&amp; <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$in"</span> &amp;&amp; <span style="font-weight: bold;">return</span>
+  <span style="font-weight: bold;">done</span>
+  select opt<span style="font-weight: bold;"> in</span> $(<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$in"</span>); <span style="font-weight: bold;">do</span>
+    [ -n <span style="font-style: italic;">"$opt"</span> ] &amp;&amp; <span style="font-weight: bold;">break</span>
+  <span style="font-weight: bold;">done</span> &gt;/dev/tty &lt;/dev/tty
+  <span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">opt</span>
+}
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orge66f5c7" class="outline-3">
+<h3 id="orge66f5c7"><span class="section-number-3">4.44</span> change loops for "mapping/reducing" functions</h3>
+<div class="outline-text-3" id="text-4-44">
+</div>
+<div id="outline-container-org94f7fb3" class="outline-4">
+<h4 id="org94f7fb3"><span class="section-number-4">4.44.1</span> find</h4>
+<div class="outline-text-4" id="text-4-44-1">
+<p>
+Many times we want to run the same operation or test to lots of
+files. Instead of looping for each file, think if <code>find -exec</code>
+would solve it. Also, find supports multiple directories.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">dirs</span>=(<span style="font-style: italic;">"/usr/local/bin"</span> <span style="font-style: italic;">"/usr/bin"</span>)
+<span style="font-weight: bold;">for</span> d<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"${dirs[@]}"</span>; <span style="font-weight: bold;">do</span>
+  <span style="font-weight: bold;">for</span> f<span style="font-weight: bold;"> in</span> $(find <span style="font-style: italic;">"$d"</span>); <span style="font-weight: bold;">do</span>
+    <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"check if owner of $f is johndoe and group is johndoe"</span>
+    [ <span style="font-weight: bold;">`stat -c %U:%G $f`</span> == <span style="font-style: italic;">"johndoe:johndoe"</span> ] || die <span style="font-style: italic;">"error"</span>
+  <span style="font-weight: bold;">done</span>
+<span style="font-weight: bold;">done</span>
+</pre>
+</div>
+
+<p>
+Compare it to:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">[ $(find <span style="font-style: italic;">"$dirs[@]"</span> -exec stat -c <span style="font-style: italic;">'%U:%G'</span> {} <span style="font-style: italic;">\;</span> | grep -vc <span style="font-style: italic;">"johndoe:johndoe"</span>) == <span style="font-style: italic;">"0"</span> ] || die <span style="font-style: italic;">"error"</span>
+</pre>
+</div>
+
+<p>
+Other examples might be:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">count all lines of all docx in this dir</span>
+find . -type f -name <span style="font-style: italic;">"*docx"</span> -exec pandoc <span style="font-style: italic;">"{}"</span> -t plain <span style="font-style: italic;">\;</span> | wc -l
+
+<span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">All your files have the same owner and group permissions</span>
+[ $(find <span style="font-style: italic;">"$files[@]"</span> -exec stat -c <span style="font-style: italic;">'%a'</span> {} <span style="font-style: italic;">\;</span> | grep -Evc <span style="font-style: italic;">"^(.)\1"</span>) == <span style="font-style: italic;">"0"</span> ]
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-orgbaab8f7" class="outline-4">
+<h4 id="orgbaab8f7"><span class="section-number-4">4.44.2</span> grep -Fvf</h4>
+<div class="outline-text-4" id="text-4-44-2">
+<p>
+Three magical flags that go well together.
+</p>
+
+<ul class="org-ul">
+<li><code>-F</code> Interpret the "pattern" as a Fixed string, not a pattern/regex</li>
+<li><code>-v</code> Negate the output. Print non matching lines.</li>
+<li><code>-f</code> The patterns to match are taken from a file.</li>
+</ul>
+
+<p>
+The cool thing about combining <code>-f</code> and <code>-v</code> is that the negative
+matches mean "lines that are not ANY of the ones in the pattern
+file". So you can do list diffing. like <code>sort + diff</code> but more
+flexible.
+</p>
+
+<p>
+Here's a practical case of finding version numbers that we have a
+git tag for, that do not have a title in the readme.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">f</span>=<span style="font-style: italic;">"readme.md"</span>
+! grep -Fvf &lt;(grep -P <span style="font-style: italic;">"^# \d\.\d\.\d\.\d$"</span> <span style="font-style: italic;">"$f"</span> | sed -e <span style="font-style: italic;">'s/^# //'</span>) <span style="font-style: italic;">\</span>
+            &lt;(git tag | grep -P <span style="font-style: italic;">"^\d\.\d\.\d\.\d$"</span>)
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-orgf574bc9" class="outline-4">
+<h4 id="orgf574bc9"><span class="section-number-4">4.44.3</span> grep -Pzo</h4>
+<div class="outline-text-4" id="text-4-44-3">
+<p>
+Three flags that also combine pretty nicely.
+</p>
+
+<p>
+With those, we can match multiple lines using plain old grep.
+</p>
+
+<p>
+This is how I get only the table structure of a postgres database.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">pg_dump -s | grep -Pzo <span style="font-style: italic;">"CREATE TABLE [^;]*;\n"</span>
+</pre>
+</div>
+
+<p>
+More info on this <a href="https://stackoverflow.com/questions/3717772/regex-grep-for-multi-line-search-needed/7167115#7167115">stackoverflow thread</a>.
+</p>
+
+
+<p>
+Use of this pattern will use <code>\0</code>'s instead of <code>\n</code>, which is good
+for the grepping, but maybe it's not good for your output. You can
+convert back <code>\0</code>'s to <code>\n</code> with <a href="https://unix.stackexchange.com/questions/121916/convert-newlines-to-null-delimited-when-using-tail">tr.</a>
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">pg_dump -s | grep -Pzo <span style="font-style: italic;">"CREATE TABLE public.($tables) [^;]*;\n"</span> | tr <span style="font-style: italic;">'\0'</span> <span style="font-style: italic;">'\n'</span> | ...
+</pre>
+</div>
+
+
+<p>
+Alternatively, depending on your requirements, you can leverage
+<code>awk</code>, with <code>awk '/CREATE TABLE/,/;/'</code>, that won't suffer from the
+\0 problem. But then you need to explain the awk model to your
+coworker.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgba1c238" class="outline-4">
+<h4 id="orgba1c238"><span class="section-number-4">4.44.4</span> grep -Ec</h4>
+<div class="outline-text-4" id="text-4-44-4">
+<p>
+Say you want to find lines that match 2 words, not just 1. in whatever order.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"foo bar"</span> | grep foo | grep bar <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">That works, but it only works for very fixed inputs.</span>
+
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"foo bar"</span> | grep -E <span style="font-style: italic;">'foo.*bar'</span>  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">That doesn't , because order matters.</span>
+
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"foo baz"</span> | grep -E <span style="font-style: italic;">'(foo|bar)'</span> | grep -E <span style="font-style: italic;">'(foo|bar)'</span> <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">That is not going to work either, because if only one word matches, it will match twice.</span>
+</pre>
+</div>
+
+<p>
+Here's how we can match multiple things from a list.
+<code>echo "foo bar" | tr ' ' '\n' |grep -Ec "(foo|bar)"</code>
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">
+<span style="font-weight: bold;">match_two</span> () {
+  <span style="font-weight: bold;">while </span><span style="font-weight: bold;">read</span> line; <span style="font-weight: bold;">do</span>
+    <span style="font-weight: bold;">if</span> [ <span style="font-style: italic;">"$(tr ' ' '\n' &lt;&lt;&lt;"$line" | rg -Uc "^($search)$")"</span> = 2 ]; <span style="font-weight: bold;">then</span>
+      <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$line"</span>
+    <span style="font-weight: bold;">fi</span>
+  <span style="font-weight: bold;">done</span>
+}
+
+cat file_with_two_words_per_line.txt | match_two <span style="font-style: italic;">"foo|bar|baz"</span>
+</pre>
+</div>
+
+<p>
+With this, you can find out how many matches happened in that
+line. The example above filters lines which have 2 words from the
+'foo|bar|baz' regex.
+</p>
+</div>
+</div>
+<div id="outline-container-orgf97a3bf" class="outline-4">
+<h4 id="orgf97a3bf"><span class="section-number-4">4.44.5</span> Set operations</h4>
+<div class="outline-text-4" id="text-4-44-5">
+<p>
+There are lots of other "set level" operations you can perform on
+files/streams using basic unix tools.
+</p>
+
+<p>
+<a href="https://catonmat.net/ftp/setops.txt">This cheatsheet</a> contains lots of them, which you should go read one by
+one, because bash, appart from being useful as it is, also has an
+Iversonian <a href="https://www.jsoftware.com/papers/tot.htm#1.2">suggestivity</a> that gets more useful with time.
+</p>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org47f30fe" class="outline-3">
+<h3 id="org47f30fe"><span class="section-number-3">4.45</span> jq</h3>
+<div class="outline-text-3" id="text-4-45">
+<p>
+Jq is more powerful than you probably think. It's not just
+to fetch a value deep into a json dictionary.
+</p>
+
+<p>
+You can fetch and transform values, and interpolate values inside
+a string template:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'{"a":1,"b":2}'</span> | jq <span style="font-style: italic;">'. | "a is \(.a), and b is \(.b)."'</span>
+</pre>
+</div>
+
+<p>
+Or use this in a map:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'[{"a":1,"b":2},{"a":3,"b":4}]'</span> | jq -r <span style="font-style: italic;">'. |map("a is \(.a), and b is \(.b).")[]'</span>
+</pre>
+</div>
+
+<p>
+Maybe a little more spicy:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'[{"host":"host1.com","user":"bob"},{"host":"host2.com","user":"alice"}]'</span> |
+  jq  <span style="font-style: italic;">'map("scp \(.user)@\(.host):/tmp/remote-file /tmp/local-file")[]'</span> -r |
+  xargs -d<span style="font-style: italic;">"\n"</span> -n1 sh -c
+</pre>
+</div>
+
+<p>
+And, make sure to read about jq functions. for example, reading nested json
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'{"nested":"{\"a\":2}"}'</span> | jq <span style="font-style: italic;">'.nested | fromjson | .a '</span>
+</pre>
+</div>
+
+<p>
+You can also edit values in place
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'{"date":1643192480}'</span> | jq <span style="font-style: italic;">'.date|=todateiso8601'</span> <span style="font-weight: bold; font-style: italic;">#  </span><span style="font-weight: bold; font-style: italic;">{"date": "2022-01-26T10:22:48Z"}</span>
+</pre>
+</div>
+
+<p>
+And we can generalize it into a filter that updates many date fields
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">join_by</span>() { local <span style="font-weight: bold; font-style: italic;">IFS</span>=<span style="font-style: italic;">"$1"</span>; <span style="font-weight: bold;">shift</span>; <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$*"</span>; }
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">usage: echo '[{"foo":1234567890,"bar":1234567891}]' | jq_pretty_dates '.[].foo' '.[].bar'</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">=&gt; [{"foo":"2009-02-13T23:31:30Z","bar":"2009-02-13T23:31:31Z"}]</span>
+<span style="font-weight: bold;">jq_pretty_dates</span>() {
+  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">From the default ($@) append every element (/%/) with</span>
+  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">|=todateiso8601). That, joined by |. And that becomes the "filter" to jq.</span>
+  jq <span style="font-style: italic;">"$(join_by "|" "${@/%/|=todateiso8601}")"</span>
+}
+</pre>
+</div>
+
+<p>
+There are quite a few interesting commands in this <a href="https://medium.com/circuitpeople/aws-cli-with-jq-and-bash-9d54e2eabaf1'">AWS+JQ post</a>.
+</p>
+
+<p>
+Some other cool tips from <a href="https://news.ycombinator.com/item?id=31141415">This HN thread</a>:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"FFFF\nDDDD"</span> | jq -R    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">reads raw text as strings. 1 line -&gt; 1 string</span>
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"FFFF\nDDDD"</span> | jq -R <span style="font-style: italic;">'capture("(?&lt;item&gt;.*)")'</span> <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">Capture groups as json elements</span>
+</pre>
+</div>
+
+<p>
+You can get pretty advanced with jq, and some say it's a decent
+substitute for <code>sed</code> as a line oriented editor.
+</p>
+
+<p>
+Some more advanced tutorials <a href="https://programminghistorian.org/en/lessons/json-and-jq">here</a> and <a href="https://remysharp.com/drafts/jq-recipes">here</a>.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgb903038" class="outline-3">
+<h3 id="orgb903038"><span class="section-number-3">4.46</span> use jq . &lt;&lt;&lt;"$var"</h3>
+<div class="outline-text-3" id="text-4-46">
+<p>
+Newlines aren't allowed in json strings, and you might get a jq
+error like:
+</p>
+
+<p>
+"parse error: Invalid string: control characters from U+0000 through U+001F must be escaped at line 148, column 99"
+</p>
+
+<p>
+Sometimes, strings inside json might have encoded newlines like <code>\n</code>. If you would use
+</p>
+
+<p>
+<code>echo $var | jq .</code> , bash would interpolate the \n inside the json
+string and when it gets to jq, it's an invalid json.
+</p>
+
+<p>
+If instead you use <code>echo -E</code>, or <code>&lt;&lt;&lt;"$var"</code>, things go smoothly.
+</p>
+
+<p>
+<code>jq . &lt;&lt;&lt;"$var"</code>
+</p>
+</div>
+</div>
+
+<div id="outline-container-orge18de62" class="outline-3">
+<h3 id="orge18de62"><span class="section-number-3">4.47</span> pass flags as a splatted array</h3>
+<div class="outline-text-3" id="text-4-47">
+<p>
+There's quite a bit to chew on this example. First of all, the core
+pattern is to build up your commandline options with an array, and
+splat it in the final command line. For complex commands like
+<code>docker</code> where you easily have 10+ flags it's a visual aid, and
+also opens up the opportunities for reusing or abstracting sets of
+options to logical blocks.
+</p>
+
+<p>
+Once it's an array, we can add elements conditionally to that array
+depending on the current run, and build the line that we'll be
+running in the end.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">Allows Ctrl-C'ing on interactive shells</span>
+<span style="font-weight: bold; font-style: italic;">INTERACTIVE</span>=
+<span style="font-weight: bold;">if</span> [[ -t 1 ]]; <span style="font-weight: bold;">then</span> <span style="font-weight: bold; font-style: italic;">INTERACTIVE</span>=<span style="font-style: italic;">"-it"</span>; <span style="font-weight: bold;">fi</span>
+
+local <span style="font-weight: bold; font-style: italic;">flags</span>=(
+  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">We mount it as read-only, so we make sure we are not writing anything</span>
+  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">in there, and that everything is explicitly defined</span>
+  <span style="font-style: italic;">"-v $LOCAL_PATH/build-dir:/build-dir:ro,delegated"</span>
+  <span style="font-style: italic;">"-v $OUTPUT_DIR:/output:rw,consistent"</span>
+  <span style="font-style: italic;">"-v $tmp_dir:/tmp/work:rw,delegated"</span>
+)
+<span style="font-weight: bold;">if</span> [[ -n $<span style="font-weight: bold; font-style: italic;">LOCAL_PATH</span> ]]; <span style="font-weight: bold;">then</span>
+  flags+=(<span style="font-style: italic;">"-v $(realpath $LOCAL_PATH)/overrides/my-other-file:/build-dir/build.json:ro"</span>)
+  flags+=(<span style="font-style: italic;">"-e LOCAL_PATH=/tmp/local"</span>)
+<span style="font-weight: bold;">fi</span>
+
+local <span style="font-weight: bold; font-style: italic;">v_id</span>=$(docker volume create)
+flags+=(<span style="font-style: italic;">"-v $v_id:/tmp/build"</span>)
+on_exit <span style="font-style: italic;">"docker volume rm $v_id"</span>
+
+docker run --rm $<span style="font-weight: bold; font-style: italic;">INTERACTIVE</span> ${<span style="font-weight: bold; font-style: italic;">flags</span>[*]} $<span style="font-weight: bold; font-style: italic;">image</span> touch /tmp/build/foo.txt
+
+docker run --rm $<span style="font-weight: bold; font-style: italic;">INTERACTIVE</span> ${<span style="font-weight: bold; font-style: italic;">flags</span>[*]} fpm:latest fpm-build /tmp/build/foo.txt
+on_exit <span style="font-style: italic;">"chown_cache $tmp_dir"</span>
+</pre>
+</div>
+
+<p>
+In this example we see another cool trick. Mounting a volume in 2
+differrent containers, so not for the purpose of sharing a local
+file/dir with the host but to share it between themselves. In that
+case, the 2 containers don't even coexist temporarily, but use the
+volume as a conveyor belt, passing it from container to container,
+and each one applies "its thing".
+</p>
+
+<p>
+After all the mess, someone has to cleanup everything, but we know
+how to do it with <code>on_exit</code> trick.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org7b4909b" class="outline-3">
+<h3 id="org7b4909b"><span class="section-number-3">4.48</span> inherit_errexit</h3>
+<div class="outline-text-3" id="text-4-48">
+<p>
+bash 4.4+ , you can <code>shopt -s inherit_errexit</code>, and subshells will
+inherit the errexit flag value. meaning that if you <code>set -Ee</code>,
+anything that runs inside a subshell will throw an error at the
+moment any command exits with <code>!=0</code>.
+</p>
+</div>
+</div>
+<div id="outline-container-org744078f" class="outline-3">
+<h3 id="org744078f"><span class="section-number-3">4.49</span> GNU Parallel</h3>
+<div class="outline-text-3" id="text-4-49">
+<p>
+I can't recommend <a href="https://www.gnu.org/software/parallel/">parallel</a> enough. The same as xargs, but in a
+much more flexible way, parallel lets you run various jobs at a
+time. If you have this tool into account, it doesn't just speed up
+your runtimes, but it will force you write cleaner code. Parallel
+execution will test your scripts so if they are not using
+randomized tmp working directories, things will clash, etc&#x2026;
+</p>
+
+<p>
+Parallel in itself is such a hackerfriendly tool it deserves to be
+deeply learned. You can use it just locally to run a process per
+core, you can send jobs to several machines connected via a simple
+ssh, you can bind tmux or sqlite to it, or you can write a trivial
+job queuing system.
+</p>
+
+<p>
+Man pages and official examples are a goldmine.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgf918892" class="outline-3">
+<h3 id="orgf918892"><span class="section-number-3">4.50</span> HEREDOCS</h3>
+<div class="outline-text-3" id="text-4-50">
+<ul class="org-ul">
+<li>Basic usage of heredocs:</li>
+</ul>
+<div class="org-src-container">
+<pre class="src src-bash">     <span style="font-weight: bold;">echo</span> &lt;&lt;EOF
+<span style="font-weight: bold;">$interpolated</span>
+<span style="font-weight: bold;">\$non_interpolated</span>
+<span style="font-weight: bold;">EOF</span>
+</pre>
+</div>
+
+<ul class="org-ul">
+<li>A dash after <code>&lt;&lt;</code> replaces trailing spaces in here docs</li>
+</ul>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">echo</span> &lt;&lt;-EOF
+<span style="font-weight: bold;">$var</span>
+<span style="font-weight: bold;">there</span>
+<span style="font-weight: bold;">EOF</span>
+</pre>
+</div>
+
+<ul class="org-ul">
+<li>quoting the identifier disables interpolation of variables</li>
+</ul>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">echo</span> &lt;&lt;<span style="font-style: italic;">'EOF'</span>
+<span style="font-weight: bold;">$non_interpolated</span>
+<span style="font-weight: bold;">there</span>
+<span style="font-weight: bold;">EOF</span>
+</pre>
+</div>
+
+<p>
+The <a href="http://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Here-Documents">bash manual</a> is super concise and to the point there.
+</p>
+
+<p>
+The most complex case is having a heredoc which contains some bash
+code that is ment to run remotely, and wanting to interpolate some
+variables in the local env, and some in the remote one. <a href="https://stackoverflow.com/questions/4937792/using-variables-inside-a-bash-heredoc">Escaping is
+enough for regular</a> vars, but if you want to use special (<code>$1, $!,
+   $?</code>&#x2026;) vars, check this out:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">deploy</span> () {
+  local <span style="font-weight: bold; font-style: italic;">deploy_dir</span>=<span style="font-style: italic;">"$1"</span>
+  ssh server1 <span style="font-style: italic;">'bash -s'</span> &lt;&lt;EOSSH
+<span style="font-weight: bold;">  echo "deploying =&gt; ${deploy_dir}"</span>
+<span style="font-weight: bold;">  ls -tdr ~/my-project/artifacts/* | head -n -5 | xargs rm -rf   # remove all but latest 5 directories</span>
+<span style="font-weight: bold;">  ln -nfs "\$HOME/my-project/artifacts/${deploy_dir}/my-project-0.1.0-SNAPSHOT-standalone.jar" "\$HOME/my-project/artifacts/current.jar"</span>
+<span style="font-weight: bold;">  cat ~/my-project/artifacts/current.pid | xargs kill</span>
+<span style="font-weight: bold;">  java -jar ~/my-project/artifacts/current.jar &amp;&gt;/dev/null &amp;</span>
+<span style="font-weight: bold;">  lastpid=\$(echo \$!)</span>
+<span style="font-weight: bold;">  echo \$lastpid &gt; ~/my-project/artifacts/current.pid</span>
+<span style="font-weight: bold;">EOSSH</span>
+}
+</pre>
+</div>
+
+<p>
+Refs: <a href="https://unix.stackexchange.com/questions/60688/how-to-defer-variable-expansion">https://unix.stackexchange.com/questions/60688/how-to-defer-variable-expansion</a>
+</p>
+</div>
+</div>
+
+<div id="outline-container-org9e3ae47" class="outline-3">
+<h3 id="org9e3ae47"><span class="section-number-3">4.51</span> HERESTRINGS</h3>
+<div class="outline-text-3" id="text-4-51">
+<p>
+It's the stripped down version of HEREDOCS. Inline a single string
+(or output of a single command) as an input string.
+</p>
+
+<p>
+It's <a href="https://stackoverflow.com/questions/18116343/whats-the-difference-between-here-string-and-echo-pipe">kinda similar</a> to what you could do with a pipe.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">cat &lt;&lt;&lt;<span style="font-style: italic;">"HELLO"</span>
+cat &lt;&lt;&lt;$(<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"HELLO"</span>)
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"ECHOPIPE"</span> | /bin/cat
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"ECHOPIPE"</span> | /bin/cat &lt;(seq 5)
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"ECHOPIPE"</span> | /bin/cat &lt;(seq 5) -
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"ECHOPIPE"</span> | /bin/cat &lt;(seq 5) &lt;&lt;&lt;<span style="font-style: italic;">"HERESTRING"</span>
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"ECHOPIPE"</span> | /bin/cat &lt;(seq 5) - &lt;&lt;&lt;<span style="font-style: italic;">"HERESTRING"</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orge8c0901" class="outline-3">
+<h3 id="orge8c0901"><span class="section-number-3">4.52</span> __DATA__</h3>
+<div class="outline-text-3" id="text-4-52">
+<p>
+I loved the Perl <a href="https://perldoc.perl.org/perldata#Special-Literals">__END__ and <span class="underline"><span class="underline">DATA</span></span></a>, features and realized it's
+possible to do it in shellscripts.
+</p>
+
+<p>
+You can append to the current file. Here's an example of a super
+simple bookmark "manager":
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">!/usr/bin/</span><span style="font-weight: bold;">env</span><span style="font-weight: bold; font-style: italic;"> sh</span>
+
+<span style="font-weight: bold;">cmd_add</span>() {
+    <span style="font-weight: bold;">shift</span>
+    <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$@"</span> &gt;&gt; <span style="font-style: italic;">"$0"</span>
+}
+
+<span style="font-weight: bold;">cmd_go</span>() {
+    sed <span style="font-style: italic;">'0,/^__DATA__$/d'</span> <span style="font-style: italic;">"$0"</span> |
+    dmenu -i -l 20  |
+    rev | cut -f1 -d<span style="font-style: italic;">' '</span> | rev |
+    xargs xdg-open
+}
+
+<span style="font-weight: bold;">main</span>() {
+    cmd_${<span style="font-weight: bold; font-style: italic;">1</span>:-go} $<span style="font-weight: bold; font-style: italic;">@</span>
+}
+
+main $<span style="font-weight: bold; font-style: italic;">@</span>
+<span style="font-weight: bold;">exit</span>
+
+__DATA__
+r/emacs             https://www.reddit.com/r/emacs
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-org1478364" class="outline-3">
+<h3 id="org1478364"><span class="section-number-3">4.53</span> Simple Templating</h3>
+<div class="outline-text-3" id="text-4-53">
+<p>
+For trivial templating, there's no need for any external tool
+except for just variable interpolation. This is quite obvious, but
+I use it quite often to generate repetitive bash code itself
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">!/usr/bin/</span><span style="font-weight: bold;">env</span><span style="font-weight: bold; font-style: italic;"> bash</span>
+<span style="font-weight: bold; font-style: italic;">is</span>=(<span style="font-style: italic;">"obj1"</span> <span style="font-style: italic;">"obj2"</span>)
+<span style="font-weight: bold; font-style: italic;">js</span>=(<span style="font-style: italic;">"resource1"</span> <span style="font-style: italic;">"resource2"</span>)
+
+<span style="font-weight: bold;">for</span> i<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"${is[@]}"</span>; <span style="font-weight: bold;">do</span>
+  <span style="font-weight: bold;">for</span> j<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"${js[@]}"</span>; <span style="font-weight: bold;">do</span>
+    <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"insert into t (obj, resource) values ('$i', '$j');"</span>
+  <span style="font-weight: bold;">done</span>
+<span style="font-weight: bold;">done</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org6deb5a1" class="outline-3">
+<h3 id="org6deb5a1"><span class="section-number-3">4.54</span> Secrets</h3>
+<div class="outline-text-3" id="text-4-54">
+<p>
+As, <a href="https://smallstep.com/blog/command-line-secrets/">Smallstep article</a> explains, you should be careful when passing
+around secret data like tokens between processes.
+</p>
+
+<p>
+Env vars are not really safe, and there are a few tricks you can
+use to cover your assets.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org2e96f17" class="outline-3">
+<h3 id="org2e96f17"><span class="section-number-3">4.55</span> Escape single quotes in single quoted strings</h3>
+<div class="outline-text-3" id="text-4-55">
+<p>
+Escaping single quoted strings doesn't work the way you'd think.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">does not work</span>
+<span style="font-weight: bold; font-style: italic;">a</span>=<span style="font-style: italic;">'hi \'</span>bob<span style="font-style: italic;">\''</span>
+</pre>
+</div>
+
+<p>
+Use <code>$''</code> strings like:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">works!</span>
+<span style="font-weight: bold; font-style: italic;">a</span>=$<span style="font-style: italic;">'hi \'</span>bob<span style="font-style: italic;">\''</span>
+<span style="font-style: italic;">echo $a</span>
+</pre>
+</div>
+
+<p>
+Extra explanations: <a href="https://stackoverflow.com/questions/1250079/how-to-escape-single-quotes-within-single-quoted-strings">StackOverflow</a>
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgfe947dc" class="outline-3">
+<h3 id="orgfe947dc"><span class="section-number-3">4.56</span> any, every, lambdas, closures, and eval</h3>
+<div class="outline-text-3" id="text-4-56">
+<p>
+Bash has no closures, and it's not "functional", but we're going to
+see how we can combine some tricks and get decent high-level functions
+</p>
+
+<p>
+Here's an implementation of <code>any</code> and <code>every</code>
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">any</span>() {
+  local <span style="font-weight: bold; font-style: italic;">pred</span>=<span style="font-style: italic;">"$1"</span>; <span style="font-weight: bold;">shift</span>
+  <span style="font-weight: bold;">for</span> i<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"$@"</span>; <span style="font-weight: bold;">do</span>
+    <span style="font-weight: bold;">if</span> $<span style="font-weight: bold; font-style: italic;">pred</span> $<span style="font-weight: bold; font-style: italic;">i</span>; <span style="font-weight: bold;">then</span>
+      <span style="font-weight: bold;">return</span> 0
+    <span style="font-weight: bold;">fi</span>
+  <span style="font-weight: bold;">done</span>
+  <span style="font-weight: bold;">return</span> 1
+}
+
+<span style="font-weight: bold;">every</span>() {
+  local <span style="font-weight: bold; font-style: italic;">pred</span>=<span style="font-style: italic;">"$1"</span>; <span style="font-weight: bold;">shift</span>
+  <span style="font-weight: bold;">for</span> i<span style="font-weight: bold;"> in</span> <span style="font-style: italic;">"$@"</span>; <span style="font-weight: bold;">do</span>
+    <span style="font-weight: bold;">if</span> ! $<span style="font-weight: bold; font-style: italic;">pred</span> $<span style="font-weight: bold; font-style: italic;">i</span>; <span style="font-weight: bold;">then</span>
+      <span style="font-weight: bold;">return</span> 1
+    <span style="font-weight: bold;">fi</span>
+  <span style="font-weight: bold;">done</span>
+  <span style="font-weight: bold;">return</span> 0
+}
+</pre>
+</div>
+
+<p>
+The usage is by passing a callback function that will return 0 or 1.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">usage</span>() {
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"help message"</span>
+}
+
+<span style="font-weight: bold;">is_help</span>() {
+  [ <span style="font-style: italic;">"$1"</span> = <span style="font-style: italic;">"--help"</span> ]
+}
+
+any is_help <span style="font-style: italic;">"$@"</span> &amp;&amp; usage
+</pre>
+</div>
+
+<p>
+That's already cool.
+</p>
+
+<p>
+Did you know that functions can start also with dashes?
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">usage</span>() {
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"help message"</span>
+}
+
+<span style="font-weight: bold;">--help</span>() {
+  [ <span style="font-style: italic;">"$1"</span> = <span style="font-style: italic;">"--help"</span> ]
+}
+
+any --help <span style="font-style: italic;">"$@"</span> &amp;&amp; usage
+</pre>
+</div>
+
+<p>
+That also works. It's kinda obfuscated a bit, but hey&#x2026;.
+</p>
+
+<p>
+We can also, with the help of <code>eval</code>, create on demand functions. They
+are global, but as we're not going to multithread, we can assume it's
+ok.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">usage</span>() {
+  <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"help message"</span>
+}
+
+<span style="font-weight: bold;">any_eq</span>() {
+  <span style="font-weight: bold;">eval</span> <span style="font-style: italic;">"_() { [ $1 = \$1 ] ; }"</span>
+  <span style="font-weight: bold;">shift</span>
+  any _  <span style="font-style: italic;">"$@"</span>
+}
+
+any_eq <span style="font-style: italic;">"--help"</span> <span style="font-style: italic;">"$@"</span> &amp;&amp; usage
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">or,</span>
+any_eq --help <span style="font-style: italic;">"$@"</span> &amp;&amp; usage
+</pre>
+</div>
+
+<p>
+And the last trick, using <code>command_not_found_handle</code>, we can get into
+a kind of rails generators for these helpers
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">command_not_found_handle</span>() {
+  <span style="font-weight: bold; font-style: italic;">IFS</span>=_ read -a cmd &lt;&lt;&lt;<span style="font-style: italic;">"$1"</span>
+  [ <span style="font-style: italic;">"eq"</span> = <span style="font-style: italic;">"${cmd[0]}"</span> ] &amp;&amp; <span style="font-weight: bold;">eval</span> <span style="font-style: italic;">"$1() { [ \"${cmd[1]}\" = \"\$1\" ] ; }"</span>
+  <span style="font-style: italic;">"$@"</span>
+}
+any eq_--help <span style="font-style: italic;">"$@"</span> &amp;&amp; usage
+</pre>
+</div>
+
+<p>
+All these last metaprogramming tricks are not thread safe, and even
+though it's mostly ok if you use them in isolation, maybe pipes or
+coprocs would mess up your inline functions.
+</p>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org85600a8" class="outline-2">
+<h2 id="org85600a8"><span class="section-number-2">5</span> Interactive</h2>
+<div class="outline-text-2" id="text-5">
+</div>
+<div id="outline-container-orgebc2ac7" class="outline-3">
+<h3 id="orgebc2ac7"><span class="section-number-3">5.1</span> Save your small scripts</h3>
+<div class="outline-text-3" id="text-5-1">
+<p>
+Rome wasn't built in a day, and like having a journal log, most of
+the little scripts you create, once you have enough discipline will
+be useful for some other cases, and your functions will be
+reusable.
+</p>
+
+<p>
+Save your scripts into files early on, instead of crunching
+everything in the repl. learn how to use a decent editor that
+shortens the feedback cycle as much as possible.
+</p>
+</div>
+</div>
+<div id="outline-container-orgd03bc18" class="outline-3">
+<h3 id="orgd03bc18"><span class="section-number-3">5.2</span> Increased Interactivity</h3>
+<div class="outline-text-3" id="text-5-2">
+<p>
+Knowing your shell's shortcuts for interactive use is a must. The
+same way you learned to touchtype and you learned your editor, you
+should learn all the shortcuts for your shell. Here's some of them.
+</p>
+
+<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
+
+
+<colgroup>
+<col  class="org-left" />
+
+<col  class="org-left" />
+</colgroup>
+<thead>
+<tr>
+<th scope="col" class="org-left">key</th>
+<th scope="col" class="org-left">action</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="org-left">Ctrl-r</td>
+<td class="org-left">reverse-history-search</td>
+</tr>
+
+<tr>
+<td class="org-left">C-a</td>
+<td class="org-left">beginning-of-line</td>
+</tr>
+
+<tr>
+<td class="org-left">C-e</td>
+<td class="org-left">end-of-line</td>
+</tr>
+
+<tr>
+<td class="org-left">C-w</td>
+<td class="org-left">delete-word-backwards</td>
+</tr>
+
+<tr>
+<td class="org-left">C-k</td>
+<td class="org-left">kill-line (from point to eol)</td>
+</tr>
+
+<tr>
+<td class="org-left">C-y</td>
+<td class="org-left">paste last killed thing</td>
+</tr>
+
+<tr>
+<td class="org-left">A-y</td>
+<td class="org-left">previous killed thing (after a c-y)</td>
+</tr>
+
+<tr>
+<td class="org-left">C-p</td>
+<td class="org-left">previous-line</td>
+</tr>
+
+<tr>
+<td class="org-left">C-n</td>
+<td class="org-left">next-line</td>
+</tr>
+
+<tr>
+<td class="org-left">A-.</td>
+<td class="org-left">insert last agument</td>
+</tr>
+
+<tr>
+<td class="org-left">A-/</td>
+<td class="org-left">dabbrev-expand</td>
+</tr>
+</tbody>
+</table>
+
+<p>
+A written form of <code>A-.</code> is <code>$_</code>. It retains the last argment and
+puts it in $_.  <code>test -f "FILE" &amp;&amp; source "$_"</code>.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgbc665f5" class="outline-3">
+<h3 id="orgbc665f5"><span class="section-number-3">5.3</span> Aliases</h3>
+<div class="outline-text-3" id="text-5-3">
+<p>
+Aliases are very simple substitutions of commands for a sequence of
+other commands.  Usual example is
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">alias <span style="font-weight: bold; font-style: italic;">ls</span>=<span style="font-style: italic;">'ls --auto-color'</span>
+</pre>
+</div>
+
+<p>
+Now let's move on to the interesting stuff.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgce75f2e" class="outline-3">
+<h3 id="orgce75f2e"><span class="section-number-3">5.4</span> functions can generate aliases</h3>
+<div class="outline-text-3" id="text-5-4">
+<p>
+Aliases live in a global namespace for the shell, so no matter
+where you define them, they take effect globally, possibly
+overwriting older aliases with the same name.
+</p>
+
+<p>
+Well, it's not lexical scope (far from it), but using aliases you
+can create a string that snapshots the value you want, and capture
+it to run it later.
+</p>
+
+<p>
+Some fun stuff:
+</p>
+
+<ul class="org-ul">
+<li>aliasgen. Create an alias for each directory in
+~/workspace/. This is superceeded by <code>CDPATH</code>, but the trick is
+still cool.</li>
+</ul>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">aliasgen</span>() {
+  <span style="font-weight: bold;">for</span> i<span style="font-weight: bold;"> in</span> ~/workspace/*(/) ; <span style="font-weight: bold;">do</span>
+      <span style="font-weight: bold; font-style: italic;">DIR</span>=$(basename $<span style="font-weight: bold; font-style: italic;">i</span>) ;
+       alias $<span style="font-weight: bold; font-style: italic;">DIR</span>=<span style="font-style: italic;">"cd ~/workspace/$i"</span>;
+  <span style="font-weight: bold;">done</span>
+}
+aliasgen
+</pre>
+</div>
+
+<ul class="org-ul">
+<li>a make a shortcut to the current directory.</li>
+</ul>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">function</span> <span style="font-weight: bold;">a</span>() { alias $<span style="font-weight: bold; font-style: italic;">1</span>=cd<span style="font-style: italic;">\ </span>$<span style="font-weight: bold; font-style: italic;">PWD</span>; }
+
+mkdir -p /tmp/fing-longer
+<span style="font-weight: bold;">cd</span> /tmp/fing-longer
+a fl
+<span style="font-weight: bold;">cd</span> /
+fl
+<span style="font-weight: bold;">echo</span> $<span style="font-weight: bold; font-style: italic;">PWD</span>   <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">/tmp/fing-longer</span>
+</pre>
+</div>
+<p>
+A man can dream&#x2026;
+</p>
+
+
+<ul class="org-ul">
+<li><p>
+unhist. functions can create aliases, and functions can receive
+functions as parameters (as a string (function name)), so we can
+combine them to advice existing functions.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">unhist</span> () {
+  alias $<span style="font-weight: bold; font-style: italic;">1</span>=<span style="font-style: italic;">" $1"</span>
+}
+unhist unhist
+unhist grep
+unhist rg
+
+<span style="font-weight: bold;">noglobber</span>() {
+    alias $<span style="font-weight: bold; font-style: italic;">1</span>=<span style="font-style: italic;">"noglob $1"</span>
+}
+noglobber http
+noglobber curl
+noglobber git
+
+</pre>
+</div></li>
+
+<li>Problem: These commands do not compose. Combination of 2 of those
+doesn't work, because the second acts just on the textual
+representation that it received, not the current value of the
+alias.</li>
+</ul>
+</div>
+</div>
+<div id="outline-container-org85375f7" class="outline-3">
+<h3 id="org85375f7"><span class="section-number-3">5.5</span> Override (advice?) common functions</h3>
+<div class="outline-text-3" id="text-5-5">
+<p>
+Overriding commands is generally a bad practice as it violates the
+principle of least surprise, but there might be occasions (mostly
+in your local machine) where you can integrate awesome finetunnings
+to your toolbelt.
+</p>
+
+<p>
+Here we're going to get the original docker binary file
+location. After that we declare a function called <code>docker</code> that
+will proxy the parameters to the original <code>docker</code> program UNLESS
+you're calling <code>docker run</code>. In that case, we're injecting a mouted
+volume that mounts <code>/root/.bash_history</code> of the container to a file
+hosted in the host (duh). That's a pretty cool way of keeping a
+history of your recent commands in your containers, no matter how
+many times you start and kill them.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">DOCKER_ORIG</span>=$(which docker)
+<span style="font-weight: bold;">docker</span> () {
+    <span style="font-weight: bold;">if</span> [[ $<span style="font-weight: bold; font-style: italic;">1</span> == <span style="font-style: italic;">"run"</span> ]]; <span style="font-weight: bold;">then</span>
+        <span style="font-weight: bold;">shift</span>
+        $<span style="font-weight: bold; font-style: italic;">DOCKER_ORIG</span> run -v $<span style="font-weight: bold; font-style: italic;">HOME</span>/.shared_bash_history:/root/.bash_history <span style="font-style: italic;">"$@"</span>
+    <span style="font-weight: bold;">else</span>
+        $<span style="font-weight: bold; font-style: italic;">DOCKER_ORIG</span> <span style="font-style: italic;">"$@"</span>
+    <span style="font-weight: bold;">fi</span>
+}
+</pre>
+</div>
+
+<p>
+I'm particularly fond of this trick, as it saved me tons of
+typing. But at a personal level, it was mindblowing that sharing
+this around the internet caused the most disparity of opinions.
+Also, I recently read the great book "Docker in Practice" by <a href="https://github.com/ianmiell">Ian
+Miell</a> and there's a snippet that is 99.9% like the one I
+created myself. That was a very cool moment.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgf1af6fd" class="outline-3">
+<h3 id="orgf1af6fd"><span class="section-number-3">5.6</span> Faster iteration on pipes</h3>
+<div class="outline-text-3" id="text-5-6">
+<p>
+When testing complex pipelines:
+</p>
+
+<ul class="org-ul">
+<li>Make them pure (no side effects).</li>
+<li>One command per line.</li>
+<li>End lines with the pipe character.</li>
+<li>During development, end the pipeline with <code>cat</code>.</li>
+</ul>
+
+<p>
+I usually use <code>watch -n1 'code.sh'</code> in a split window so I see the
+results of what I'm doing. The advantage of
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">curl https://www.example.com/videos/              |
+  pup <span style="font-style: italic;">'figure.mg &gt; a attr{href}'</span>                  |
+  head -1                                         |
+  xargs -I{} curl -L <span style="font-style: italic;">"https://www.example.com/{}"</span> |
+  pup <span style="font-style: italic;">'script'</span>                                    |
+  grep file:                                      |
+  sed -e <span style="font-style: italic;">"s/.*\(http[^ \"']*\).*/\1/"</span>             |
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">xargs vlc                                       |</span>
+  cat
+</pre>
+</div>
+
+<p>
+Over
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">curl https://www.example.com/videos/                <span style="font-style: italic;">\</span>
+  | pup <span style="font-style: italic;">'figure.mg &gt; a attr{href}'</span>                  <span style="font-style: italic;">\</span>
+  | head -1                                         <span style="font-style: italic;">\</span>
+  | xargs -I{} curl -L <span style="font-style: italic;">"https://www.example.com/{}"</span> <span style="font-style: italic;">\</span>
+  | pup <span style="font-style: italic;">'script'</span>                                    <span style="font-style: italic;">\</span>
+  | grep file:                                      <span style="font-style: italic;">\</span>
+  | sed -e <span style="font-style: italic;">"s/.*\(http[^ \"']*\).*/\1/"</span>             <span style="font-style: italic;">\</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">xargs vlc   # doesn't work</span>
+</pre>
+</div>
+
+<p>
+Is that you can comment out lines on the former one, but you can't
+do that on the latter. The <code>cat</code> trick makes it so that you have an
+'exit' point, and you don't have to comment that one. Also, some
+editors will indent the first one correctly, while you'll have to
+manually indent the second one.
+</p>
+
+<p>
+Small wins that compose just fine :)
+</p>
+</div>
+</div>
+
+<div id="outline-container-org3709c91" class="outline-3">
+<h3 id="org3709c91"><span class="section-number-3">5.7</span> Use ${var?error msg} on templates</h3>
+<div class="outline-text-3" id="text-5-7">
+<p>
+If you write something to be copypasted by your user and filled in,
+instead of <code>&lt;var&gt;</code>, try <code>${var?You need to set var}</code>. it allows for the user to set
+the variable in the environment without having to replace inline,
+and if the user forgets any, the shell will barf.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgf8108b7" class="outline-3">
+<h3 id="orgf8108b7"><span class="section-number-3">5.8</span> Idempotent functions</h3>
+<div class="outline-text-3" id="text-5-8">
+<p>
+Being able to call the same function multiple times even if you just
+called it, without having to account for "oh, did this already happen
+or not?" but instead have a mental model of "I need this to have
+happened after this function call", and consider it done, is very
+liberating from the code perspective.
+</p>
+
+<p>
+Also, there are subgoals, like caching slow functions, downloads, etc.
+</p>
+</div>
+
+<div id="outline-container-org45726e5" class="outline-4">
+<h4 id="org45726e5"><span class="section-number-4">5.8.1</span> nop subsequent calls</h4>
+<div class="outline-text-4" id="text-5-8-1">
+<p>
+"My favourite shell scripting function definition technique:
+idempotent functions by redefining the function as a noop inside
+its body:
+</p>
+
+<p>
+(The `true;` body is needed by some shells, e.g. bash, and not
+others, e.g. zsh.)  " &#x2013; <a href="https://news.ycombinator.com/item?id=27729397">chrismorgan</a>
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">foo</span>() {
+    foo() { true; }
+    <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"This bit will only be executed on the first foo call"</span>
+}
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-orgce65206" class="outline-4">
+<h4 id="orgce65206"><span class="section-number-4">5.8.2</span> Download once</h4>
+<div class="outline-text-4" id="text-5-8-2">
+<p>
+A function might be sideffecty, as in "download files". These sort of
+cases, you want to download the file only if you haven't downloaded it
+yet.
+</p>
+
+<p>
+<code>cache</code> here gets a cache "id" where it'll store the results of <code>http</code>
+and next time, when called with the same param, it will reuse the saved version.
+</p>
+
+<p>
+This pattern applies to many kinds of functions, so with slight
+modifications you can adapt it.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">cache</span>() {
+  local <span style="font-weight: bold; font-style: italic;">path</span>=$<span style="font-weight: bold; font-style: italic;">CACHE_DIR</span>/$<span style="font-weight: bold; font-style: italic;">1</span>
+  [[ -f $<span style="font-weight: bold; font-style: italic;">path</span> ]] &amp;&amp; cat $<span style="font-weight: bold; font-style: italic;">path</span> &amp;&amp; <span style="font-weight: bold;">return</span> 0
+
+  <span style="font-weight: bold;">shift</span>
+  $<span style="font-weight: bold; font-style: italic;">@</span> | tee $<span style="font-weight: bold; font-style: italic;">path</span>
+
+  <span style="font-weight: bold;">return</span> 1
+}
+
+<span style="font-weight: bold;">get_repos</span>() {
+  local <span style="font-weight: bold; font-style: italic;">url</span>=<span style="font-style: italic;">"https://api.github.com/search/repositories?q=user:$USER&amp;access_token=$GITHUB_TOKEN&amp;per_page=100&amp;page=$1"</span>
+  cache $<span style="font-weight: bold; font-style: italic;">USER</span>-repos-$<span style="font-weight: bold; font-style: italic;">1</span> http $<span style="font-weight: bold; font-style: italic;">url</span>
+}
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orgb384a40" class="outline-4">
+<h4 id="orgb384a40"><span class="section-number-4">5.8.3</span> memoize with ttl, with ttl</h4>
+<div class="outline-text-4" id="text-5-8-3">
+<p>
+What if you want to cache for some time?
+</p>
+
+<p>
+The tricks here:
+</p>
+
+<ul class="org-ul">
+<li>Use a file as a sentinel for the cache.</li>
+<li>Create a file, set it's modification date to now()+12hours</li>
+<li>check with `-nt` (newer than) and a temporary file (to have a
+<code>now()</code> value in "file" format).</li>
+</ul>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">hmacache</span>=<span style="font-style: italic;">"/tmp/.hmacache"</span>
+<span style="font-weight: bold;">is_recent_cache</span>() {
+  [ <span style="font-style: italic;">"$hmacache"</span> -nt &lt;(<span style="font-weight: bold;">echo</span> 1) ]
+}
+<span style="font-weight: bold;">update_cache</span>() {
+  touch -m -t <span style="font-style: italic;">"$(date -v+12H +"%Y%m%d%H%M.%S")"</span> <span style="font-style: italic;">"$hmacache"</span>
+}
+
+<span style="font-weight: bold;">main</span>() {
+  <span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">...</span>
+  <span style="font-weight: bold;">if</span> ! is_recent_cache ; <span style="font-weight: bold;">then</span>
+    <span style="font-weight: bold;">if</span> ! curl -s https://hello.ts.net &gt; /dev/null; <span style="font-weight: bold;">then</span>
+      die <span style="font-style: italic;">"Tailscale must be connected to start Harbormaster"</span>
+    <span style="font-weight: bold;">fi</span>
+    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">other slow checks</span>
+    update_cache
+  <span style="font-weight: bold;">fi</span>
+}
+</pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org1d488c7" class="outline-2">
+<h2 id="org1d488c7"><span class="section-number-2">6</span> Debugging</h2>
+<div class="outline-text-2" id="text-6">
+</div>
+<div id="outline-container-org766f8db" class="outline-3">
+<h3 id="org766f8db"><span class="section-number-3">6.1</span> adding <code>bash</code> to a script to debug</h3>
+<div class="outline-text-3" id="text-6-1">
+<p>
+You can add <code>bash</code> inside any script, and it'll add a sort of
+a breakpoint, allowing you to check the state of the env and
+manually call functions around.
+</p>
+
+<p>
+If you orgainse your code in small functions, it's easy to add
+breakpoints by just spawning bash processes inside your script.
+</p>
+
+<p>
+This works also inside docker containers (if you provide <code>-ti</code> flag
+on run).
+</p>
+
+<p>
+Let's see some usual uses of docker and how we can debug our
+scripts there:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">leaves you at a shell to fiddle if all is in place after build</span>
+docker run -it mycomplex-image bash
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">Runs /tmp/file.sh from the host inside. That's cool to make the</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">container less airtight. Even if the image is not originally meant</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">to, you can even override it and 'monkeypatch' the file with the one</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">from the host anyway.</span>
+docker run -it -v $<span style="font-weight: bold; font-style: italic;">PWD</span>:/tmp/ mycomplex-image /tmp/file.sh
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">So now you can really add wtv you want there.</span>
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'bash'</span> &gt;&gt;$<span style="font-weight: bold; font-style: italic;">PWD</span>/file.sh
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">run+open shell at runtime to inspect the state of the script</span>
+docker run -it -v $<span style="font-weight: bold; font-style: italic;">PWD</span>:/tmp/ mycomplex-image /tmp/file.sh
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orgb9cc112" class="outline-3">
+<h3 id="orgb9cc112"><span class="section-number-3">6.2</span> DRY_RUN</h3>
+<div class="outline-text-3" id="text-6-2">
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">if</span> [[-n <span style="font-style: italic;">"$DRY_RUN"</span> ]]; <span style="font-weight: bold;">then</span>
+  curl () {
+    <span style="font-weight: bold;">echo</span> curl <span style="font-style: italic;">"$@"</span>
+  }
+<span style="font-weight: bold;">fi</span>
+</pre>
+</div>
+<p>
+use <code>command curl</code> to force the command, not the alias or anything
+</p>
+
+<p>
+If you have many functions to mock, and you want to overabstract (bad thing):
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">
+<span style="font-weight: bold;">mock</span>() {
+  <span style="font-weight: bold;">for</span> m<span style="font-weight: bold;"> in</span> ${<span style="font-weight: bold; font-style: italic;">MOCKS</span>[@]//,/ }; <span style="font-weight: bold;">do</span>
+    <span style="font-weight: bold;">eval</span> <span style="font-style: italic;">"$m() { echo \"mocked $m\" "\$</span><span style="font-weight: bold; font-style: italic;">@</span><span style="font-style: italic;">"; }"</span>
+  <span style="font-weight: bold;">done</span>
+}
+
+<span style="font-weight: bold; font-style: italic;">MOCKS</span>=curl,ls script.sh
+</pre>
+</div>
+</div>
+</div>
+
+
+
+<div id="outline-container-org99348e1" class="outline-3">
+<h3 id="org99348e1"><span class="section-number-3">6.3</span> Cheap debugging flag</h3>
+<div class="outline-text-3" id="text-6-3">
+<div class="org-src-container">
+<pre class="src src-bash">optargs <span style="font-style: italic;">"V"</span> option; <span style="font-weight: bold;">do</span>
+<span style="font-weight: bold;">case</span> $<span style="font-weight: bold; font-style: italic;">option</span><span style="font-weight: bold;"> in</span>
+  V)
+    <span style="font-weight: bold;">set</span> -xa
+  ;;
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orgcde2971" class="outline-3">
+<h3 id="orgcde2971"><span class="section-number-3">6.4</span> explore a pipe with tee &gt;(some_command) |</h3>
+<div class="outline-text-3" id="text-6-4">
+<p>
+the <code>&gt;()</code> is not very easy to use. Very few places where it
+fits. Here's a nice pipe inspector though, using <code>tee &gt;(cat 1&gt;&amp;2)</code>
+trick.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">plog</span>() {
+  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">tee &gt;(cat 1&gt;&amp;2)</span>
+  local <span style="font-weight: bold; font-style: italic;">msg</span>=${<span style="font-weight: bold; font-style: italic;">1</span>:-plog}
+  tee &gt;(sed -e <span style="font-style: italic;">"s/^/[$msg] /"</span> 1&gt;&amp;2)
+}
+alias -g <span style="font-style: italic;">'PL'</span>=<span style="font-style: italic;">' |plog '</span> <span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">zsh only</span>
+
+<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"a\nb"</span> PL foo | tr <span style="font-style: italic;">'a-z'</span> <span style="font-style: italic;">'A-Z'</span> PL bar
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">output:</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">[foo] a     # stderr</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">[foo] b     # stderr</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">A           # stdout</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">B           # stdout</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">[bar] A     # stderr</span>
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">[bar] b     # stderr</span>
+</pre>
+</div>
+
+
+<p>
+ref: <a href="https://stackoverflow.com/questions/17983777/shell-pipe-to-multiple-commands-in-a-file">https://stackoverflow.com/questions/17983777/shell-pipe-to-multiple-commands-in-a-file</a>
+</p>
+</div>
+</div>
+
+<div id="outline-container-org3d85028" class="outline-3">
+<h3 id="org3d85028"><span class="section-number-3">6.5</span> tee+sudo</h3>
+<div class="outline-text-3" id="text-6-5">
+<p>
+If you wat to store a file in a root-owned dir, in the middle of
+your pipeline, instead of running the whole thing as root, you can
+use <code>sudo tee file</code>:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">ls | grep m &gt;/usr/local/garbage  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">fail</span>
+ls | grep m | sudo tee /usr/local/garbage <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">success!</span>
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-org4c63237" class="outline-3">
+<h3 id="org4c63237"><span class="section-number-3">6.6</span> quoting</h3>
+<div class="outline-text-3" id="text-6-6">
+<p>
+Bash: To get a quoted version of a given string, here's what you can do:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">this is my "string" I want to 'comment "on"'</span>
+!:q
+</pre>
+</div>
+
+<p>
+That gives us <code>'#this is my "string" I want to '\''comment
+   "on"'\'''</code>. Neat!
+</p>
+
+<p>
+I just found this trick <a href="https://til.simonwillison.net/til/til/bash_escaping-a-string.md">here</a>. From the associated HN thread:
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">function</span> <span style="font-weight: bold;">bashquote</span> () {
+  printf <span style="font-style: italic;">'%q'</span> <span style="font-style: italic;">"$(cat)"</span>
+  <span style="font-weight: bold;">echo</span>
+}
+</pre>
+</div>
+
+<p>
+Zsh: If you're on zsh, <code>a-'</code> quotes the current line.
+</p>
+</div>
+</div>
+</div>
+<div id="outline-container-org34f68f7" class="outline-2">
+<h2 id="org34f68f7"><span class="section-number-2">7</span> zsh-only</h2>
+<div class="outline-text-2" id="text-7">
+</div>
+<div id="outline-container-org2aae8cd" class="outline-3">
+<h3 id="org2aae8cd"><span class="section-number-3">7.1</span> Word spliting</h3>
+<div class="outline-text-3" id="text-7-1">
+<p>
+Word splitting works differently by default in zsh than in bash.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold; font-style: italic;">foo</span>=<span style="font-style: italic;">"ls -las"</span>
+$<span style="font-weight: bold; font-style: italic;">foo</span>
+</pre>
+</div>
+<p>
+This works in bash, but zsh will not split by words. To make zsh
+expand by words, there are 2 ways: <code>setopt SH_WORD_SPLIT</code> and
+<code>${=foo}</code>.  zsh has <code>unsetop</code> command, which allows to scope where
+you want the expansions to happen. <code>unsetop SH_WORD_SPLIT</code>.
+</p>
+
+<p>
+The problem with both solutions is that none of them are compatible
+with bash, so you'll be cornering yourself to "this only works in
+zsh".  A way to overcome this is to use arrays, which are expanded
+in the same way in both shells.
+</p>
+
+<p>
+Or, use the same hack as you'll see later with noglob.
+</p>
+
+<p>
+Refs:
+</p>
+<ul class="org-ul">
+<li><a href="https://stackoverflow.com/questions/6715388/variable-expansion-is-different-in-zsh-from-that-in-bash">https://stackoverflow.com/questions/6715388/variable-expansion-is-different-in-zsh-from-that-in-bash</a></li>
+<li><a href="http://zsh.sourceforge.net/FAQ/zshfaq03.html#l18">http://zsh.sourceforge.net/FAQ/zshfaq03.html#l18</a></li>
+</ul>
+</div>
+</div>
+<div id="outline-container-orga4ecce6" class="outline-3">
+<h3 id="orga4ecce6"><span class="section-number-3">7.2</span> globbing</h3>
+<div class="outline-text-3" id="text-7-2">
+<p>
+In zsh, getting a list of files that match some characteristics is
+doable using globbing. Bash has globbing also, but in a less sophisticated way.
+</p>
+
+<p>
+The basic structure of a <code>glob</code> is <code>pattern(qualifiers)</code>. Patterns
+can contain:
+</p>
+<ul class="org-ul">
+<li>strings: they do exact match</li>
+<li>wildcards:  <code>*</code>, <code>?</code>, <code>**/</code></li>
+<li>character classes: <code>[0-9]</code></li>
+<li>choices:  <code>(.pdf|.djvu)</code></li>
+</ul>
+
+<p>
+The qualifiers are extra constraints you put on the matches. There
+are lots of different qualifiers. Look at <code>zshexpn</code> for the
+complete list. The ones I use more are:
+</p>
+
+<ul class="org-ul">
+<li><code>.</code> Files</li>
+<li><code>/</code> Directories</li>
+<li><code>om[numberhere]</code>. Nth latest modified</li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-orga8080f2" class="outline-3">
+<h3 id="orga8080f2"><span class="section-number-3">7.3</span> Global aliases:</h3>
+<div class="outline-text-3" id="text-7-3">
+<p>
+Zsh has 3 kinds of aliases: normal, global, and suffix. Normal ones
+behave the same as in bash: They expand only in the first token of
+a line.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">alias <span style="font-weight: bold; font-style: italic;">foo</span>=ls
+foo foo <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">-&gt; ls: cannot access 'foo': No such file or directory</span>
+</pre>
+</div>
+
+<p>
+Global aliases expand anywhere in your cli, and they can expand to
+anything.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">alias  -g <span style="font-weight: bold; font-style: italic;">foo</span>=ls
+foo foo <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">-&gt; ls: cannot access 'ls': No such file or directory</span>
+</pre>
+</div>
+
+<p>
+These are some aliases I have in my ~/.zshrc that help me use a
+shell in a more fluid way.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">alias -g <span style="font-weight: bold; font-style: italic;">P1</span>=<span style="font-style: italic;">'| awk "{print \$1}"'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">P2</span>=<span style="font-style: italic;">'| awk "{print \$2}"'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">P3</span>=<span style="font-style: italic;">'| awk "{print \$3}"'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">P4</span>=<span style="font-style: italic;">'| awk "{print \$4}"'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">P5</span>=<span style="font-style: italic;">'| awk "{print \$5}"'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">P6</span>=<span style="font-style: italic;">'| awk "{print \$6}"'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">PL</span>=<span style="font-style: italic;">'| awk "{print \$NF}"'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">PN</span>=<span style="font-style: italic;">'| awk "{print \$NF}"'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">HL</span>=<span style="font-style: italic;">'| head -20'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">H</span>=<span style="font-style: italic;">'| head '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">H1</span>=<span style="font-style: italic;">'| head -1'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">TL</span>=<span style="font-style: italic;">'| tail -20'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">T</span>=<span style="font-style: italic;">'| tail '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">T1</span>=<span style="font-style: italic;">'T -1'</span>
+<span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">alias -g tr='-ltr'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">X</span>=<span style="font-style: italic;">'| xclip  '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">TB</span>=<span style="font-style: italic;">'| nc termbin.com 9999 '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">L</span>=<span style="font-style: italic;">'| less -R '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">LR</span>=<span style="font-style: italic;">'| less -r '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">G</span>=<span style="font-style: italic;">'| grep '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">GI</span>=<span style="font-style: italic;">'| grep -i '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">GG</span>=<span style="font-style: italic;">' 2&gt;&amp;1 | grep '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">GGI</span>=<span style="font-style: italic;">' 2&gt;&amp;1 | grep -i '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">GV</span>=<span style="font-style: italic;">'| grep -v '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">V</span>=<span style="font-style: italic;">'| grep -v '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">TAC</span>=<span style="font-style: italic;">'| tac '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">DU</span>=<span style="font-style: italic;">'du -B1'</span>
+
+alias -g <span style="font-weight: bold; font-style: italic;">E2O</span>=<span style="font-style: italic;">' 2&gt;&amp;1 '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">NE</span>=<span style="font-style: italic;">' 2&gt;/dev/null '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">NO</span>=<span style="font-style: italic;">' &gt;/dev/null '</span>
+
+alias -g <span style="font-weight: bold; font-style: italic;">WC</span>=<span style="font-style: italic;">'| wc -l '</span>
+
+alias -g <span style="font-weight: bold; font-style: italic;">J</span>=<span style="font-style: italic;">'| noglob jq'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">JQ</span>=<span style="font-style: italic;">'| noglob jq'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">jq</span>=<span style="font-style: italic;">'noglob jq'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">JL</span>=<span style="font-style: italic;">'| noglob jq -C . | less -R '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">JQL</span>=<span style="font-style: italic;">'| noglob jq -C . | less -R '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">XMEL</span>=<span style="font-style: italic;">'| xmlstarlet el'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">XML</span>=<span style="font-style: italic;">'| xmlstarlet sel -t -v '</span>
+
+alias -g <span style="font-weight: bold; font-style: italic;">LYNX</span>=<span style="font-style: italic;">"| lynx -dump -stdin "</span>
+alias -g <span style="font-weight: bold; font-style: italic;">H2T</span>=<span style="font-style: italic;">"| html2text "</span>
+alias -g <span style="font-weight: bold; font-style: italic;">TRIM</span>=<span style="font-style: italic;">"| xargs "</span>
+alias -g <span style="font-weight: bold; font-style: italic;">XA</span>=<span style="font-style: italic;">'| xargs -d"\n" '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">XE</span>=<span style="font-style: italic;">"| xargs e"</span>
+alias -g <span style="font-weight: bold; font-style: italic;">P</span>=<span style="font-style: italic;">"| pick "</span>
+alias -g <span style="font-weight: bold; font-style: italic;">PP</span>=<span style="font-style: italic;">"| percol | xargs "</span>
+alias -g <span style="font-weight: bold; font-style: italic;">W5</span>=<span style="font-style: italic;">"watch -n5 "</span>
+alias -g <span style="font-weight: bold; font-style: italic;">W1</span>=<span style="font-style: italic;">"watch -n1 "</span>
+
+
+alias -g <span style="font-weight: bold; font-style: italic;">CB</span>=<span style="font-style: italic;">"| col -b "</span>
+alias -g <span style="font-weight: bold; font-style: italic;">NC</span>=<span style="font-style: italic;">"| col -b "</span>
+alias -g <span style="font-weight: bold; font-style: italic;">U</span>=<span style="font-style: italic;">'| uniq '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">XT</span>=<span style="font-style: italic;">'urxvt -e '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">DM</span>=<span style="font-style: italic;">'| dmenu '</span>
+alias -g <span style="font-weight: bold; font-style: italic;">DMV</span>=<span style="font-style: italic;">'| dmenu -i -l 20 '</span>
+
+alias -g ...=<span style="font-style: italic;">'../..'</span>
+alias -g ....=<span style="font-style: italic;">'../../..'</span>
+alias -g .....=<span style="font-style: italic;">'../../../..'</span>
+
+alias -g <span style="font-weight: bold; font-style: italic;">l10</span>=<span style="font-style: italic;">'*(om[1,10])'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">l20</span>=<span style="font-style: italic;">'*(om[1,20])'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">l5</span>=<span style="font-style: italic;">'*(om[1,5])'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">l</span>=<span style="font-style: italic;">'*(om[1])'</span>
+alias -g <span style="font-style: italic;">'**.'</span>=<span style="font-style: italic;">'**/*(.)'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">lpdf</span>=<span style="font-style: italic;">'*.pdf(om[1])'</span>
+alias -g <span style="font-weight: bold; font-style: italic;">lpng</span>=<span style="font-style: italic;">'*.png(om[1])'</span>
+
+alias -g <span style="font-weight: bold; font-style: italic;">u</span>=<span style="font-style: italic;">'*(om[1])'</span>
+
+alias <span style="font-weight: bold; font-style: italic;">lsmov</span>=<span style="font-style: italic;">'ls *.(mp4|mpg|mpeg|avi|mkv)'</span>
+alias <span style="font-weight: bold; font-style: italic;">lspdf</span>=<span style="font-style: italic;">'ls *.(pdf|djvu)'</span>
+alias <span style="font-weight: bold; font-style: italic;">lsmp3</span>=<span style="font-style: italic;">'ls *.mp3'</span>
+alias <span style="font-weight: bold; font-style: italic;">lspng</span>=<span style="font-style: italic;">'ls *.png'</span>
+</pre>
+</div>
+<p>
+Now, some sequences of words can start making sense:
+</p>
+
+<ul class="org-ul">
+<li><code>lspdf -tr TL DM XA evince</code></li>
+<li><code>docker exec -u root -ti $(docker ps -q H1) bash</code></li>
+<li><code>docker ps DM P1 XA docker stop</code></li>
+<li><code>docker ps P1 XA docker stop</code> (P1 XA does an ad-hoc <a href="https://bash-my-aws.org/pipe-skimming/">pipe-skimming</a>)</li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-org3746252" class="outline-3">
+<h3 id="org3746252"><span class="section-number-3">7.4</span> Expansion of global aliases</h3>
+<div class="outline-text-3" id="text-7-4">
+<p>
+Let's dig deeper.
+</p>
+<div class="org-src-container">
+<pre class="src src-zsh">alias -g DOCK='docker ps 2..N P P1'
+DOCK  # works fine. Echoes the id of the chosen container
+docker stop DOCK   # does not work , because it expands to docker stop docker ps 2..N P P1
+docker stop $(DOCK) # works fine again
+alias -g DOCK='$(docker ps 2..N P P1)'
+docker stop DOCK   # yay!
+</pre>
+</div>
+
+<p>
+So, you can bind words to expansion-time results of the aliases. It
+feels like a very powerful thing, to have this "compile time"
+expansions. Reminds me of CL's symbol-macrolet, or IMMEDIATE Forth
+words.
+</p>
+</div>
+</div>
+<div id="outline-container-org33f98b5" class="outline-3">
+<h3 id="org33f98b5"><span class="section-number-3">7.5</span> Autocomplete</h3>
+<div class="outline-text-3" id="text-7-5">
+<p>
+Writting smart autocompletion scripts is not easy.
+</p>
+
+<p>
+zsh supports <code>compdef _gnu_generic</code> type of completion, which gets
+you very far with 0 effort.
+</p>
+
+<p>
+When autocompleting after a <code>-</code> in the commandline, if your command
+is configured like <code>compdef _gnu_generic mycommand</code>, zsh will call
+the script with <code>--help</code> and parse the output, trying to find
+flags, and will use them as suggestions. It's really great.
+</p>
+
+<p>
+The compromise is to write a decent "&#x2013;help" for your script. Which
+is cool because your user will love it too, and you just have to
+write it once.
+</p>
+
+<p>
+The completion is not context aware though, so you can't
+autocomplete flags after the first non-flag argument. It seems this
+could be improved in zsh-land, by asking for the &#x2013;help like
+<code>mycommand args-so-far --help</code>. But it doesn't work like that.
+</p>
+
+
+<div class="org-src-container">
+<pre class="src src-zsh">#!/usr/bin/env bash
+# The script can be bash-only, while the completion work in zsh-only
+set -Eeuo pipefail
+
+help() {
+  echo "  -h,--help    Show help"
+  echo "  -c,--command Another thing"
+}
+
+if [ "$1" == "--help" ];
+  help
+fi
+</pre>
+</div>
+
+<p>
+Now you can play with <code>mycommand -&lt;TAB&gt;</code>. Amazing, wow.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org0d3209d" class="outline-3">
+<h3 id="org0d3209d"><span class="section-number-3">7.6</span> Create helpers and generate global aliases automagically</h3>
+<div class="outline-text-3" id="text-7-6">
+<p>
+Borrowing a bit from Perl, a bit from Forth, and a bit from
+PicoLisp, I've come to create a few helpers that abstract words
+into a bit higher level concepts. Unifying the option selectors is
+one, and then, other line oriented operations like <code>chomp, from,
+   till</code>.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash"><span style="font-weight: bold;">pick</span>() {
+  <span style="font-weight: bold;">if</span> [ -z <span style="font-style: italic;">"$DISPLAY"</span> ]; <span style="font-weight: bold;">then</span>
+    percol || fzf || slmenu -i -l 20
+  <span style="font-weight: bold;">else</span>
+    dmenu -i -l 20
+  <span style="font-weight: bold;">fi</span>
+}
+alias -g <span style="font-weight: bold; font-style: italic;">P</span>=<span style="font-style: italic;">'| pick'</span>
+
+<span style="font-weight: bold;">globalias</span>() {
+  alias -g <span style="font-weight: bold;">`echo -n $1 | tr '[a-z]' '[A-Z]'`</span>=<span style="font-style: italic;">" | $1 "</span>
+}
+
+globalias fzf
+
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">uniquify column</span>
+<span style="font-weight: bold;">function</span> <span style="font-weight: bold;">uc</span> () {
+  awk -F<span style="font-style: italic;">" "</span> <span style="font-style: italic;">"!_[\$$1]++"</span>
+}
+globalias uc
+
+<span style="font-weight: bold;">function</span> <span style="font-weight: bold;">from</span>() { perl -pe <span style="font-style: italic;">"s|.*?$1|\1|"</span> }
+globalias from
+
+<span style="font-weight: bold;">function</span> <span style="font-weight: bold;">till</span>() { sed -e <span style="font-style: italic;">"s|$1.*|$1|"</span> }
+globalias till
+
+<span style="font-weight: bold;">function</span> <span style="font-weight: bold;">chomp</span> () { sed -e <span style="font-style: italic;">"s|.$||"</span> }
+globalias chomp
+</pre>
+</div>
+
+<p>
+Again, it's a pity those do not compose well. Just be well
+organized, or build a more elaborate hack so you can compose
+aliases with some sort of confidence. It'll always be a hack
+though.
+</p>
+</div>
+</div>
+<div id="outline-container-org5b1403e" class="outline-3">
+<h3 id="org5b1403e"><span class="section-number-3">7.7</span> suffix aliases don't have to match a filename</h3>
+<div class="outline-text-3" id="text-7-7">
+<p>
+zsh has another type of aliases called "suffix alias". Those alias
+allow you to define programs to open/run file types.
+</p>
+<div class="org-src-container">
+<pre class="src src-shell">alias -s <span style="font-weight: bold; font-style: italic;">docx</span>=<span style="font-style: italic;">"libreoffice"</span>
+</pre>
+</div>
+
+<p>
+With this said, if you write a name of a file ending with <code>docx</code> as
+the first token in a command line, it will use libreoffice to open
+it.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-shell">invoice1.docx
+<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">will effectively call libreoffice invoice1.docx</span>
+</pre>
+</div>
+
+<p>
+The trick here is that the parser doesn't check that the file is
+indeed an existing file. It can be any string.
+</p>
+
+<p>
+Let's look at an example of it.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-shell">alias -s <span style="font-weight: bold; font-style: italic;">git</span>=<span style="font-style: italic;">"git clone"</span>
+</pre>
+</div>
+
+<p>
+In this case, we can easily copy a <code>git@github.com:.....git</code> from a
+browser, and paste it into a zsh console. Then, zsh will run that
+"file" with the command <code>git clone</code>, effectively cloning that
+repository.
+</p>
+
+<p>
+Cool, ain't it?
+</p>
+</div>
+</div>
+
+<div id="outline-container-org7a453b9" class="outline-3">
+<h3 id="org7a453b9"><span class="section-number-3">7.8</span> noglob</h3>
+<div class="outline-text-3" id="text-7-8">
+<p>
+zsh has more aggressive parameter expansion, to the level that
+<code>[,],...</code> have special meanings, and will be interpreted and
+expanded before calling the final commands in your shell.
+</p>
+
+<p>
+There are commands that you don't want ever expanded , for example,
+when using <code>curl</code>, it's much more likely that an open bracket will
+be ment to be there verbatim rather than expanded.
+</p>
+
+<p>
+Zsh provides a command to quote the following expansions. And it's
+called noglob.
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">noglob curl http://example.com<span style="font-style: italic;">\&amp;</span>a[]=1
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org66a71b7" class="outline-3">
+<h3 id="org66a71b7"><span class="section-number-3">7.9</span> make noglob 'transparent' to bash</h3>
+<div class="outline-text-3" id="text-7-9">
+<p>
+zsh and bash are mostly compatible, but there's a few things not
+supported in bash. <code>noglob</code> is one of them. To build a shim
+inbetween, an easy way is to just create a <code>~/bin/noglob</code> file
+</p>
+<div class="org-src-container">
+<pre class="src src-bash">$<span style="font-weight: bold; font-style: italic;">*</span>
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-orge0f04ad" class="outline-3">
+<h3 id="orge0f04ad"><span class="section-number-3">7.10</span> glob nested expansion</h3>
+<div class="outline-text-3" id="text-7-10">
+<p>
+In <a href="https://news.ycombinator.com/item?id=26175894">https://news.ycombinator.com/item?id=26175894</a> there's a nice
+advanced example:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-text">Variable expansion syntax, glob qualifiers, and history modifiers can
+be combined/nested quite nicely. For example, this outputs all the
+commands available from $PATH: `echo
+${~${path/%/\/*(*N:t)}}`. `${~foo}` is to enable glob expansion on the
+result of foo. `${foo/%/bar}` substitutes the end of the result of foo
+to "bar" (i.e. it appends it); when foo is an array, it does it for
+each element. In `/*(*N:t)`, we're adding the slash and star to the
+paths from `$path`, then the parentheses are glob qualifiers. `*`
+inside means only match the executables, `N` is to activate NULL_GLOB
+for the match so that we don't get errors for globs that didn't match
+anything, `:t` is a history mod used for globs that returns just the
+"tail" of the result, i.e. the basename. IIRC, bash can't even nest
+multiple parameter expansions; you need to save each step separately.
+</pre>
+</div>
+</div>
+</div>
+<div id="outline-container-orga113df8" class="outline-3">
+<h3 id="orga113df8"><span class="section-number-3">7.11</span> Some extra shortcuts for nice things</h3>
+<div class="outline-text-3" id="text-7-11">
+<ul class="org-ul">
+<li><code>alt-'</code> quotes the current line. It's like <code>quotemeta</code>. great to
+help you fight double and triple quoting when writing scripts.</li>
+<li><code>alt-#</code> comment/uncomment and execute. Nice way to store the current line
+for later and reach out to it again to run it for real.</li>
+<li><code>ctrl-o</code> kill-current-line, wait for a command, and paste.</li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-org686bf61" class="outline-3">
+<h3 id="org686bf61"><span class="section-number-3">7.12</span> =()</h3>
+<div class="outline-text-3" id="text-7-12">
+<p>
+Zsh has <code>&lt;()</code> and <code>&gt;()</code> like Bash, but it also has <code>=()</code>. This
+varant is similar to <code>&lt;()</code> but instead of creating a temporary
+pipe, it creates a temporary file. That is useful if we want to run
+commands that require a file instead of a pipe (most times, because
+it uses lseek to go through it).
+</p>
+
+<p>
+Node is an example of this.
+</p>
+<div class="org-src-container">
+<pre class="src src-shell">node &lt;(<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'setTimeout(() =&gt; console.log("foo"), 400)'</span>)   <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">fails</span>
+node =(<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">'setTimeout(() =&gt; console.log("foo"), 400)'</span>)   <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">works!</span>
+</pre>
+</div>
+
+<p>
+Or,
+</p>
+
+<div class="org-src-container">
+<pre class="src src-bash">docker run --rm -ti -v =(<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"OHAI"</span>):/tmp/foo ubuntu cat /tmp/foo
+</pre>
+</div>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org691d1e2" class="outline-2">
+<h2 id="org691d1e2"><span class="section-number-2">8</span> <span class="todo TODO">TODO</span> patterns</h2>
+<div class="outline-text-2" id="text-8">
+</div>
+<div id="outline-container-orgc1d8b98" class="outline-3">
+<h3 id="orgc1d8b98"><span class="section-number-3">8.1</span> just use cat/netcat/pipes with &lt;()</h3>
+<div class="outline-text-3" id="text-8-1">
+<ul class="org-ul">
+<li><p>
+input
+</p>
+
+<p>
+<code>python logger.py executable</code> will run the executable and monitor it
+for error messages. Depending on the error messages it will be doing.
+</p>
+
+<p>
+In order to test it, I want to run it with my own output. So what I
+do is <code>python logger.py cat</code>. That way I can type my stuff there,
+and even better, I can use a stream from the shell. <code>myexecutable |
+  python logger.py cat</code> still works.
+</p></li>
+</ul>
+</div>
+
+<div id="outline-container-org2e1e61c" class="outline-4">
+<h4 id="org2e1e61c"><span class="section-number-4">8.1.1</span> what's the unifying theory behind all that?</h4>
+<div class="outline-text-4" id="text-8-1-1">
+<p>
+It's still not clear to me how they relate, but the feeling is
+that there's a common thread ruling all those commands. as if they
+generalize over the same things, or just a couple of very
+interrelated things.
+</p>
+
+<p>
+<code>echo</code> is to <code>cat</code> what <code>|</code> is to <code>xargs</code>. and <code>&lt;()</code> and <code>&gt;()</code> are
+able to make static files be dynamic streams. putting <code>cat</code> and
+<code>echo</code> inside <code>&lt;()</code> seem like either a noop, or a leap in what can
+be done there. Still have to figure it out.
+</p>
+
+<p>
+&lt;(grep a file.txt) , | xargs , cat, echo
+</p>
+<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
+
+
+<colgroup>
+<col  class="org-left" />
+
+<col  class="org-left" />
+
+<col  class="org-left" />
+
+<col  class="org-left" />
+</colgroup>
+<tbody>
+<tr>
+<td class="org-left">you-have\it-wants</td>
+<td class="org-left">executable</td>
+<td class="org-left">file</td>
+<td class="org-left">stream</td>
+</tr>
+
+<tr>
+<td class="org-left">executable</td>
+<td class="org-left">X</td>
+<td class="org-left">&lt;(exe)</td>
+<td class="org-left">exe &vert;</td>
+</tr>
+
+<tr>
+<td class="org-left">file</td>
+<td class="org-left">&lt;(cat file)</td>
+<td class="org-left">X</td>
+<td class="org-left">cat file &vert;</td>
+</tr>
+
+<tr>
+<td class="org-left">stream</td>
+<td class="org-left">cat</td>
+<td class="org-left">&lt;(grep foo file.txt)</td>
+<td class="org-left">X</td>
+</tr>
+</tbody>
+</table>
+
+
+<ul class="org-ul">
+<li><p>
+output
+</p>
+
+<p>
+Most of those can be tested with and <code>tee</code>. Sometimes you would like
+the output to be an output to a file to be extramassaged.
+</p>
+
+<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
+
+
+<colgroup>
+<col  class="org-left" />
+
+<col  class="org-left" />
+
+<col  class="org-left" />
+
+<col  class="org-left" />
+</colgroup>
+<tbody>
+<tr>
+<td class="org-left">you-have\it-wants</td>
+<td class="org-left">executable</td>
+<td class="org-left">file</td>
+<td class="org-left">stream</td>
+</tr>
+
+<tr>
+<td class="org-left">executable</td>
+<td class="org-left">X</td>
+<td class="org-left">&gt;()</td>
+<td class="org-left">&#xa0;</td>
+</tr>
+
+<tr>
+<td class="org-left">file</td>
+<td class="org-left">&#xa0;</td>
+<td class="org-left">X</td>
+<td class="org-left">&#xa0;</td>
+</tr>
+
+<tr>
+<td class="org-left">stream</td>
+<td class="org-left">&#xa0;</td>
+<td class="org-left">&gt;(cat)</td>
+<td class="org-left">X</td>
+</tr>
+</tbody>
+</table>
+
+<p>
+lnav &lt;(tail -F /my/logfile-that-gets-rotated-or-truncated.log)
+cat &lt;(date)
+</p></li>
+</ul>
+</div>
+</div>
+</div>
+
+<div id="outline-container-org1056b1d" class="outline-3">
+<h3 id="org1056b1d"><span class="section-number-3">8.2</span> redirects &amp; streams</h3>
+<div class="outline-text-3" id="text-8-2">
+<ul class="org-ul">
+<li><a href="https://catonmat.net/ftp/bash-redirections-cheat-sheet.pdf">https://catonmat.net/ftp/bash-redirections-cheat-sheet.pdf</a></li>
+<li><a href="https://catonmat.net/bash-one-liners-explained-part-three">https://catonmat.net/bash-one-liners-explained-part-three</a></li>
+<li><a href="https://github.com/miguelmota/bash-streams-handbook">https://github.com/miguelmota/bash-streams-handbook</a></li>
+<li><a href="https://www2.dmst.aueb.gr/dds/sw/dgsh/">https://www2.dmst.aueb.gr/dds/sw/dgsh/</a></li>
+<li><a href="https://wiki.bash-hackers.org/howto/redirection_tutorial">https://wiki.bash-hackers.org/howto/redirection_tutorial</a></li>
+</ul>
+</div>
+</div>
+<div id="outline-container-org763dc7e" class="outline-3">
+<h3 id="org763dc7e"><span class="section-number-3">8.3</span> The $0 pattern</h3>
+<div class="outline-text-3" id="text-8-3">
+<ul class="org-ul">
+<li><a href="https://www.reddit.com/r/oilshell/comments/f6of85/four_more_posts_in_shell_the_good_parts/">https://www.reddit.com/r/oilshell/comments/f6of85/four_more_posts_in_shell_the_good_parts/</a></li>
+</ul>
+</div>
+</div>
+<div id="outline-container-org18b2ff5" class="outline-3">
+<h3 id="org18b2ff5"><span class="section-number-3">8.4</span> use git staging area to diff outputs of commands</h3>
+<div class="outline-text-3" id="text-8-4">
+<ul class="org-ul">
+<li><a href="https://chrismorgan.info/blog/make-and-git-diff-test-harness/">https://chrismorgan.info/blog/make-and-git-diff-test-harness/</a></li>
+<li><a href="https://news.ycombinator.com/item?id=32896051">Content based change detection with Make</a></li>
+<li><a href="https://news.ycombinator.com/item?id=40333481">https://news.ycombinator.com/item?id=40333481</a></li>
+<li><a href="https://news.ycombinator.com/item?id=32441602">https://news.ycombinator.com/item?id=32441602</a></li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-orgeb2aacd" class="outline-3">
+<h3 id="orgeb2aacd"><span class="section-number-3">8.5</span> coprocs</h3>
+<div class="outline-text-3" id="text-8-5">
+<ul class="org-ul">
+<li><a href="https://stackoverflow.com/questions/7942632/how-to-extrace-pg-backend-pid-from-postgresql-in-shell-script-and-pass-it-to-ano/8305578#8305578">https://stackoverflow.com/questions/7942632/how-to-extrace-pg-backend-pid-from-postgresql-in-shell-script-and-pass-it-to-ano/8305578#8305578</a></li>
+<li><a href="https://unix.stackexchange.com/questions/86270/how-do-you-use-the-command-coproc-in-various-shells">https://unix.stackexchange.com/questions/86270/how-do-you-use-the-command-coproc-in-various-shells</a></li>
+<li><a href="https://mbuki-mvuki.org/posts/2021-05-30-memoize-commands-or-bash-functions-with-coprocs/">https://mbuki-mvuki.org/posts/2021-05-30-memoize-commands-or-bash-functions-with-coprocs/</a></li>
+</ul>
+</div>
+</div>
+</div>
+<div id="outline-container-org6331da9" class="outline-2">
+<h2 id="org6331da9"><span class="section-number-2">9</span> links</h2>
+<div class="outline-text-2" id="text-9">
+<ul class="org-ul">
+<li><a href="https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html">https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html</a></li>
+<li><a href="https://www.gnu.org/software/bash/manual/html_node/">https://www.gnu.org/software/bash/manual/html_node/</a></li>
+<li><a href="https://tldp.org/LDP/abs/html/">https://tldp.org/LDP/abs/html/</a></li>
+<li><a href="https://mywiki.wooledge.org/BashPitfalls">https://mywiki.wooledge.org/BashPitfalls</a></li>
+<li><a href="https://www.youtube.com/watch?v=sCZJblyT_XM">Gary Bernhardt. The Unix Chainsaw</a></li>
+<li><a href="https://github.com/spencertipping/">https://github.com/spencertipping/</a>. This guy has some bash sick snippets</li>
+<li><a href="https://news.ycombinator.com/item?id=23765123">https://news.ycombinator.com/item?id=23765123</a></li>
+<li><a href="https://medium.com/@joydeepubuntu/functional-programming-in-bash-145b6db336b7">https://medium.com/@joydeepubuntu/functional-programming-in-bash-145b6db336b7</a></li>
+<li><a href="https://www.youtube.com/watch?v=yD2ekOEP9sU">https://www.youtube.com/watch?v=yD2ekOEP9sU</a></li>
+<li><a href="http://catern.com/posts/pipes.html">http://catern.com/posts/pipes.html</a></li>
+<li><a href="https://ebzzry.io/en/zsh-tips-1/">https://ebzzry.io/en/zsh-tips-1/</a></li>
+<li><a href="https://github.com/ssledz/bash-fun">https://github.com/ssledz/bash-fun</a></li>
+<li><a href="https://news.ycombinator.com/item?id=24556022">https://news.ycombinator.com/item?id=24556022</a></li>
+<li><a href="https://www.datafix.com.au/BASHing/index.html">https://www.datafix.com.au/BASHing/index.html</a></li>
+<li><a href="https://susam.github.io/tucl/the-unix-command-language.html">https://susam.github.io/tucl/the-unix-command-language.html</a></li>
+<li><a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html">https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html</a></li>
+<li><a href="https://www.grymoire.com/Unix/Sh.html">https://www.grymoire.com/Unix/Sh.html</a></li>
+<li><a href="https://github.com/dylanaraps/pure-sh-bible">https://github.com/dylanaraps/pure-sh-bible</a></li>
+<li><a href="https://github.com/dylanaraps/pure-bash-bible">https://github.com/dylanaraps/pure-bash-bible</a></li>
+<li><a href="https://shatterealm.netlify.app/programming/2021_01_02_shiv_lets_build_a_vcs">https://shatterealm.netlify.app/programming/2021_01_02_shiv_lets_build_a_vcs</a></li>
+<li><a href="https://news.ycombinator.com/item?id=24401085">https://news.ycombinator.com/item?id=24401085</a></li>
+<li><a href="https://git.sr.ht/~sircmpwn/shit">https://git.sr.ht/~sircmpwn/shit</a></li>
+<li><a href="https://github.com/p8952/bocker">bocker</a>. Docker implemented in around 100 lines of bash.</li>
+<li><a href="https://github.com/simplenetes-io/simplenetes">https://github.com/simplenetes-io/simplenetes</a> wow</li>
+<li><a href="https://bakkenbaeck.github.io/a-random-walk-through-git/">https://bakkenbaeck.github.io/a-random-walk-through-git/</a></li>
+<li><a href="https://github.com/WeilerWebServices/Bash">https://github.com/WeilerWebServices/Bash</a></li>
+<li><a href="https://www.netmeister.org/blog/consistent-tools.html">https://www.netmeister.org/blog/consistent-tools.html</a>.</li>
+<li><a href="https://www.arp242.net/why-zsh.html">https://www.arp242.net/why-zsh.html</a>. bash vs zsh differences.</li>
+<li><a href="https://dwheeler.com/essays/filenames-in-shell.html">https://dwheeler.com/essays/filenames-in-shell.html</a></li>
+<li><a href="https://lacker.io/math/2022/02/24/godels-incompleteness-in-bash.html">https://lacker.io/math/2022/02/24/godels-incompleteness-in-bash.html</a></li>
+<li><a href="https://www.evalapply.org/posts/shell-aint-a-bad-place-to-fp-part-1-doug-mcilroys-pipeline/">https://www.evalapply.org/posts/shell-aint-a-bad-place-to-fp-part-1-doug-mcilroys-pipeline/</a> (from <a href="https://clojurians.slack.com/archives/C03RZGPG3/p1645563940203839">clojurians slack</a>)</li>
+<li><a href="https://github.com/adityaathalye">https://github.com/adityaathalye</a></li>
+<li><a href="https://www.youtube.com/watch?v=BJ0uHhBkzOQ">https://www.youtube.com/watch?v=BJ0uHhBkzOQ</a></li>
+<li><a href="https://www.gnu.org/software/autoconf/manual/autoconf-2.60/html_node/Portable-Shell.html">https://www.gnu.org/software/autoconf/manual/autoconf-2.60/html_node/Portable-Shell.html</a></li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-org434fe9d" class="outline-2">
+<h2 id="org434fe9d"><span class="section-number-2">10</span> From shell to lisp and everything in between</h2>
+<div class="outline-text-2" id="text-10">
+<ul class="org-ul">
+<li><a href="https://github.com/oilshell/oil">Oil Shell</a>.</li>
+<li><a href="https://rash-lang.org/">Rash</a> (Racket shell)</li>
+<li><a href="https://arxiv.org/pdf/2007.09436.pdf">PaSh</a>: Light-touch Data-Parallel Shell Processing.</li>
+<li><a href="https://www.eigenbahn.com/2020/07/08/painless-emacs-remote-shells">Painless emacs remote shells</a>. Because emacs has you covered</li>
+<li><a href="https://news.ycombinator.com/item?id=24249646">https://news.ycombinator.com/item?id=24249646</a> rust</li>
+<li><a href="https://github.com/liljencrantz/crush">https://github.com/liljencrantz/crush</a></li>
+<li><a href="https://github.com/artyom-poptsov/metabash">https://github.com/artyom-poptsov/metabash</a></li>
+<li><a href="https://www.nushell.sh/">https://www.nushell.sh/</a></li>
+<li><a href="https://github.com/borkdude/babashka">Babashka</a></li>
+<li>Bash to Perl/Python/Ruby using <code>``</code> and growing from there.</li>
+</ul>
+</div>
+</div>
+<div id="outline-container-org059781e" class="outline-2">
+<h2 id="org059781e"><span class="section-number-2">11</span> Credits</h2>
+<div class="outline-text-2" id="text-11">
+<ul class="org-ul">
+<li>Raimon Grau &lt;<a href="mailto:raimonster@gmail.com">raimonster@gmail.com</a>&gt;.</li>
+<li>Some examples are result of Raimon's and Lluís Esquerda's
+conversations or real world examples.</li>
+<li>people in <a href="https://news.ycombinator.com/item?id=24402571">https://news.ycombinator.com/item?id=24402571</a> which I'll
+be pulling in as time allows.</li>
+</ul>
+</div>
+</div>
+</div>
+<div id="postamble" class="status">
+<p class="author">Author: Raimon Grau</p>
+<p class="creator"><a href="https://www.gnu.org/software/emacs/">Emacs</a> 26.1 (<a href="https://orgmode.org">Org</a> mode 9.1.9)</p>
+<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
+</div>
+</body>
+</html>
diff --git a/readme.org b/readme.org
new file mode 100644
index 0000000..3ab8d38
--- /dev/null
+++ b/readme.org
@@ -0,0 +1 @@
+* https://kidd.github.io/scripting-field-guide/index.html
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..4d3c133
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,5790 @@
+<style type="text/css">
+    <!--
+      body {
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-adict-conditional-text {
+        /* adict-conditional-text-face */
+        background-color: #0000cd;
+      }
+      .org-alert-high {
+        /* alert-high-face */
+        color: #ff8c00;
+        font-weight: bold;
+      }
+      .org-alert-low {
+        /* alert-low-face */
+        color: #00008b;
+      }
+      .org-alert-moderate {
+        /* alert-moderate-face */
+        color: #ffd700;
+        font-weight: bold;
+      }
+      .org-alert-normal {
+      }
+      .org-alert-saved-fringe {
+        /* alert-saved-fringe-face */
+        background-color: #f2f2f2;
+      }
+      .org-alert-trivial {
+        /* alert-trivial-face */
+        color: #9400d3;
+      }
+      .org-alert-urgent {
+        /* alert-urgent-face */
+        color: #ff0000;
+        font-weight: bold;
+      }
+      .org-apropos-keybinding {
+        /* apropos-keybinding */
+        text-decoration: underline;
+      }
+      .org-apropos-property {
+        /* apropos-property */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-apropos-symbol {
+        /* apropos-symbol */
+        font-weight: bold;
+      }
+      .org-battery-load-critical {
+        /* battery-load-critical */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-battery-load-low {
+        /* battery-load-low */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-beacon-fallback-background {
+        /* beacon-fallback-background */
+        background-color: #ffffff;
+      }
+      .org-bgXerc-color-face0 {
+        /* bg:erc-color-face0 */
+        background-color: #ffffff;
+      }
+      .org-bgXerc-color-face1 {
+        /* bg:erc-color-face1 */
+        background-color: #000000;
+      }
+      .org-bgXerc-color-face10 {
+        /* bg:erc-color-face10 */
+        background-color: #bfefff;
+      }
+      .org-bgXerc-color-face11 {
+        /* bg:erc-color-face11 */
+        background-color: #00ffff;
+      }
+      .org-bgXerc-color-face12 {
+        /* bg:erc-color-face12 */
+        background-color: #0000ff;
+      }
+      .org-bgXerc-color-face13 {
+        /* bg:erc-color-face13 */
+        background-color: #ff1493;
+      }
+      .org-bgXerc-color-face14 {
+        /* bg:erc-color-face14 */
+        background-color: #7f7f7f;
+      }
+      .org-bgXerc-color-face15 {
+        /* bg:erc-color-face15 */
+        background-color: #e5e5e5;
+      }
+      .org-bgXerc-color-face2 {
+        /* bg:erc-color-face2 */
+        background-color: #00008b;
+      }
+      .org-bgXerc-color-face3 {
+        /* bg:erc-color-face3 */
+        background-color: #008b00;
+      }
+      .org-bgXerc-color-face4 {
+        /* bg:erc-color-face4 */
+        background-color: #ff0000;
+      }
+      .org-bgXerc-color-face5 {
+        /* bg:erc-color-face5 */
+        background-color: #a52a2a;
+      }
+      .org-bgXerc-color-face6 {
+        /* bg:erc-color-face6 */
+        background-color: #a020f0;
+      }
+      .org-bgXerc-color-face7 {
+        /* bg:erc-color-face7 */
+        background-color: #ffa500;
+      }
+      .org-bgXerc-color-face8 {
+        /* bg:erc-color-face8 */
+        background-color: #ffff00;
+      }
+      .org-bgXerc-color-face9 {
+        /* bg:erc-color-face9 */
+        background-color: #00ff00;
+      }
+      .org-bm {
+        /* bm-face */
+        color: #3F3F3F;
+        background-color: #E0CF9F;
+      }
+      .org-bm-fringe {
+        /* bm-fringe-face */
+        color: #3F3F3F;
+        background-color: #E0CF9F;
+      }
+      .org-bm-fringe-persistent {
+        /* bm-fringe-persistent-face */
+        color: #3F3F3F;
+        background-color: #5F7F5F;
+      }
+      .org-bm-persistent {
+        /* bm-persistent-face */
+        color: #3F3F3F;
+        background-color: #5F7F5F;
+      }
+      .org-bold {
+        /* bold */
+        font-weight: bold;
+      }
+      .org-bold-italic {
+        /* bold-italic */
+        font-weight: bold;
+        font-style: italic;
+      }
+      .org-bookmark-menu-bookmark {
+        /* bookmark-menu-bookmark */
+        font-weight: bold;
+      }
+      .org-bookmark-menu-heading {
+        /* bookmark-menu-heading */
+        color: #7CB8BB;
+      }
+      .org-border {
+      }
+      .org-browse-url-button {
+        /* browse-url-button */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-buffer-menu-buffer {
+        /* buffer-menu-buffer */
+        font-weight: bold;
+      }
+      .org-builtin {
+        /* font-lock-builtin-face */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-button {
+        /* button */
+        text-decoration: underline;
+      }
+      .org-c-annotation {
+        /* c-annotation-face */
+        color: #BFEBBF;
+      }
+      .org-c-nonbreakable-space {
+        /* c-nonbreakable-space-face */
+        background-color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-calc-nonselected {
+        /* calc-nonselected-face */
+        color: #b3b3b3;
+        font-style: italic;
+      }
+      .org-calc-selected {
+        /* calc-selected-face */
+        font-weight: bold;
+      }
+      .org-calendar-month-header {
+        /* calendar-month-header */
+        color: #93E0E3;
+      }
+      .org-calendar-today {
+        /* calendar-today */
+        text-decoration: underline;
+      }
+      .org-calendar-weekday-header {
+        /* calendar-weekday-header */
+        color: #BFEBBF;
+      }
+      .org-calendar-weekend-header {
+        /* calendar-weekend-header */
+        color: #7F9F7F;
+      }
+      .org-change-log-acknowledgment {
+        /* change-log-acknowledgment */
+        color: #7F9F7F;
+      }
+      .org-change-log-conditionals {
+        /* change-log-conditionals */
+        color: #DFAF8F;
+      }
+      .org-change-log-date {
+        /* change-log-date */
+        color: #CC9393;
+      }
+      .org-change-log-email {
+        /* change-log-email */
+        color: #DFAF8F;
+      }
+      .org-change-log-file {
+        /* change-log-file */
+        color: #93E0E3;
+      }
+      .org-change-log-function {
+        /* change-log-function */
+        color: #DFAF8F;
+      }
+      .org-change-log-list {
+        /* change-log-list */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-change-log-name {
+        /* change-log-name */
+        color: #BFEBBF;
+      }
+      .org-child-frame-border {
+      }
+      .org-cider-debug-code-overlay {
+        /* cider-debug-code-overlay-face */
+        background-color: #4d4d4d;
+      }
+      .org-cider-debug-prompt {
+        /* cider-debug-prompt-face */
+        color: #DCDCCC;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-cider-deprecated {
+        /* cider-deprecated-face */
+        background-color: #D0BF8F;
+      }
+      .org-cider-docview-emphasis {
+        /* cider-docview-emphasis-face */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+        text-decoration: underline;
+      }
+      .org-cider-docview-literal {
+        /* cider-docview-literal-face */
+        color: #CC9393;
+      }
+      .org-cider-docview-strong {
+        /* cider-docview-strong-face */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-cider-docview-table-border {
+        /* cider-docview-table-border-face */
+        color: #b3b3b3;
+      }
+      .org-cider-enlightened {
+      }
+      .org-cider-enlightened-local {
+        /* cider-enlightened-local-face */
+        color: #8FB28F;
+        font-weight: bold;
+      }
+      .org-cider-error-highlight {
+        /* cider-error-highlight-face */
+        text-decoration: underline;
+      }
+      .org-cider-fragile-button {
+        /* cider-fragile-button-face */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-cider-fringe-good {
+        /* cider-fringe-good-face */
+        color: #BFEBBF;
+      }
+      .org-cider-instrumented {
+      }
+      .org-cider-reader-conditional {
+        /* cider-reader-conditional-face */
+        color: #7F9F7F;
+      }
+      .org-cider-repl-input {
+        /* cider-repl-input-face */
+        font-weight: bold;
+      }
+      .org-cider-repl-prompt {
+        /* cider-repl-prompt-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-cider-repl-result {
+      }
+      .org-cider-repl-stderr {
+        /* cider-repl-stderr-face */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-cider-repl-stdout {
+        /* cider-repl-stdout-face */
+        color: #CC9393;
+      }
+      .org-cider-result-overlay {
+      }
+      .org-cider-stacktrace {
+        /* cider-stacktrace-face */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-cider-stacktrace-error-class {
+        /* cider-stacktrace-error-class-face */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-cider-stacktrace-error-message {
+        /* cider-stacktrace-error-message-face */
+        color: #9FC59F;
+      }
+      .org-cider-stacktrace-filter-active {
+        /* cider-stacktrace-filter-active-face */
+        text-decoration: underline;
+      }
+      .org-cider-stacktrace-filter-inactive {
+      }
+      .org-cider-stacktrace-fn {
+        /* cider-stacktrace-fn-face */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+        font-weight: bold;
+      }
+      .org-cider-stacktrace-ns {
+        /* cider-stacktrace-ns-face */
+        color: #7F9F7F;
+      }
+      .org-cider-stacktrace-promoted-button {
+        /* cider-stacktrace-promoted-button-face */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-cider-stacktrace-suppressed-button {
+        /* cider-stacktrace-suppressed-button-face */
+        color: #b3b3b3;
+      }
+      .org-cider-test-error {
+        /* cider-test-error-face */
+        background-color: #DC8CC3;
+      }
+      .org-cider-test-failure {
+        /* cider-test-failure-face */
+        background-color: #8C5353;
+      }
+      .org-cider-test-success {
+        /* cider-test-success-face */
+        background-color: #5F7F5F;
+      }
+      .org-cider-traced {
+      }
+      .org-cider-warning-highlight {
+        /* cider-warning-highlight-face */
+        text-decoration: underline;
+      }
+      .org-clojure-character {
+        /* clojure-character-face */
+        color: #CC9393;
+      }
+      .org-clojure-keyword {
+        /* clojure-keyword-face */
+        color: #BFEBBF;
+      }
+      .org-comint-highlight-input {
+        /* comint-highlight-input */
+        font-weight: bold;
+      }
+      .org-comint-highlight-prompt {
+        /* comint-highlight-prompt */
+        color: #F0DFAF;
+      }
+      .org-comment {
+        /* font-lock-comment-face */
+        color: #7F9F7F;
+      }
+      .org-comment-delimiter {
+        /* font-lock-comment-delimiter-face */
+        color: #5F7F5F;
+      }
+      .org-company-echo {
+      }
+      .org-company-echo-common {
+        /* company-echo-common */
+        color: #ff3030;
+      }
+      .org-company-preview {
+        /* company-preview */
+        background-color: #9FC59F;
+      }
+      .org-company-preview-common {
+        /* company-preview-common */
+        color: #9FC59F;
+        background-color: #2B2B2B;
+      }
+      .org-company-preview-search {
+        /* company-preview-search */
+        background-color: #0000ff;
+      }
+      .org-company-scrollbar-bg {
+        /* company-scrollbar-bg */
+        background-color: #5F5F5F;
+      }
+      .org-company-scrollbar-fg {
+        /* company-scrollbar-fg */
+        background-color: #2B2B2B;
+      }
+      .org-company-template-field {
+        /* company-template-field */
+        color: #000000;
+        background-color: #ffff00;
+      }
+      .org-company-tooltip {
+        /* company-tooltip */
+        color: #DCDCCC;
+        background-color: #4F4F4F;
+      }
+      .org-company-tooltip-annotation {
+        /* company-tooltip-annotation */
+        color: #DFAF8F;
+        background-color: #4F4F4F;
+      }
+      .org-company-tooltip-annotation-selection {
+        /* company-tooltip-annotation-selection */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+      }
+      .org-company-tooltip-common {
+        /* company-tooltip-common */
+        color: #9FC59F;
+      }
+      .org-company-tooltip-common-selection {
+        /* company-tooltip-common-selection */
+        color: #9FC59F;
+      }
+      .org-company-tooltip-mouse {
+        /* company-tooltip-mouse */
+        background-color: #2B2B2B;
+      }
+      .org-company-tooltip-search {
+        /* company-tooltip-search */
+        background-color: #383838;
+      }
+      .org-company-tooltip-search-selection {
+        /* company-tooltip-search-selection */
+        background-color: #383838;
+      }
+      .org-company-tooltip-selection {
+        /* company-tooltip-selection */
+        color: #DCDCCC;
+        background-color: #2B2B2B;
+      }
+      .org-compilation-column-number {
+        /* compilation-column-number */
+        color: #9FC59F;
+      }
+      .org-compilation-error {
+        /* compilation-error */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-compilation-info {
+        /* compilation-info */
+        color: #BFEBBF;
+        text-decoration: underline;
+      }
+      .org-compilation-line-number {
+        /* compilation-line-number */
+        color: #F0DFAF;
+      }
+      .org-compilation-mode-line-exit {
+        /* compilation-mode-line-exit */
+        color: #9FC59F;
+        font-weight: bold;
+      }
+      .org-compilation-mode-line-fail {
+        /* compilation-mode-line-fail */
+        color: #CC9393;
+        font-weight: bold;
+      }
+      .org-compilation-mode-line-run {
+        /* compilation-mode-line-run */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-compilation-warning {
+        /* compilation-warning */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-completions-annotations {
+        /* completions-annotations */
+        color: #656555;
+      }
+      .org-completions-common-part {
+        /* completions-common-part */
+        color: #add8e6;
+      }
+      .org-completions-first-difference {
+        /* completions-first-difference */
+        font-weight: bold;
+      }
+      .org-constant {
+        /* font-lock-constant-face */
+        color: #BFEBBF;
+      }
+      .org-counsel--mark-ring-highlight {
+        /* counsel-mark-ring-highlight */
+        background-color: #383838;
+      }
+      .org-counsel-active-mode {
+        /* counsel-active-mode */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-counsel-application-name {
+        /* counsel-application-name */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-counsel-evil-register {
+        /* counsel-evil-register-face */
+        color: #DFAF8F;
+        background-color: #3F3F3F;
+      }
+      .org-counsel-key-binding {
+        /* counsel-key-binding */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-counsel-outline-1 {
+        /* counsel-outline-1 */
+        color: #DFAF8F;
+        background-color: #3F3F3F;
+      }
+      .org-counsel-outline-2 {
+        /* counsel-outline-2 */
+        color: #BFEBBF;
+        background-color: #3F3F3F;
+      }
+      .org-counsel-outline-3 {
+        /* counsel-outline-3 */
+        color: #7CB8BB;
+        background-color: #3F3F3F;
+      }
+      .org-counsel-outline-4 {
+        /* counsel-outline-4 */
+        color: #D0BF8F;
+        background-color: #3F3F3F;
+      }
+      .org-counsel-outline-5 {
+        /* counsel-outline-5 */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+      }
+      .org-counsel-outline-6 {
+        /* counsel-outline-6 */
+        color: #9FC59F;
+        background-color: #3F3F3F;
+      }
+      .org-counsel-outline-7 {
+        /* counsel-outline-7 */
+        color: #8C5353;
+        background-color: #3F3F3F;
+      }
+      .org-counsel-outline-8 {
+        /* counsel-outline-8 */
+        color: #4C7073;
+        background-color: #3F3F3F;
+      }
+      .org-counsel-outline-default {
+        /* counsel-outline-default */
+        color: #F0DFAF;
+      }
+      .org-counsel-variable-documentation {
+        /* counsel-variable-documentation */
+        color: #7F9F7F;
+      }
+      .org-cov-coverage-not-run {
+        /* cov-coverage-not-run-face */
+        color: #ff0000;
+      }
+      .org-cov-coverage-run {
+        /* cov-coverage-run-face */
+        color: #00ff00;
+      }
+      .org-cov-heavy {
+        /* cov-heavy-face */
+        color: #ff0000;
+      }
+      .org-cov-light {
+        /* cov-light-face */
+        color: #00ff00;
+      }
+      .org-cov-med {
+        /* cov-med-face */
+        color: #ffff00;
+      }
+      .org-cov-none {
+        /* cov-none-face */
+        color: #0000ff;
+      }
+      .org-css-property {
+        /* css-property */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-css-selector {
+        /* css-selector */
+        color: #93E0E3;
+      }
+      .org-cua-global-mark {
+        /* cua-global-mark */
+        color: #000000;
+        background-color: #ffff00;
+      }
+      .org-cua-rectangle {
+        /* cua-rectangle */
+        color: #ffffff;
+        background-color: #b03060;
+      }
+      .org-cua-rectangle-noselect {
+        /* cua-rectangle-noselect */
+        color: #ffffff;
+        background-color: #696969;
+      }
+      .org-cursor {
+        /* cursor */
+        color: #DCDCCC;
+        background-color: #FFFFEF;
+      }
+      .org-custom-button {
+        /* custom-button */
+        color: #000000;
+        background-color: #d3d3d3;
+      }
+      .org-custom-button-mouse {
+        /* custom-button-mouse */
+        color: #000000;
+        background-color: #e5e5e5;
+      }
+      .org-custom-button-pressed {
+        /* custom-button-pressed */
+        color: #000000;
+        background-color: #d3d3d3;
+      }
+      .org-custom-button-pressed-unraised {
+        /* custom-button-pressed-unraised */
+        color: #ee82ee;
+        text-decoration: underline;
+      }
+      .org-custom-button-unraised {
+        /* custom-button-unraised */
+        text-decoration: underline;
+      }
+      .org-custom-changed {
+        /* custom-changed */
+        color: #ffffff;
+        background-color: #0000ff;
+      }
+      .org-custom-comment {
+        /* custom-comment */
+        background-color: #696969;
+      }
+      .org-custom-comment-tag {
+        /* custom-comment-tag */
+        color: #cccccc;
+      }
+      .org-custom-documentation {
+      }
+      .org-custom-face-tag {
+        /* custom-face-tag */
+        color: #8CD0D3;
+        font-weight: bold;
+      }
+      .org-custom-group-subtitle {
+        /* custom-group-subtitle */
+        font-weight: bold;
+      }
+      .org-custom-group-tag {
+        /* custom-group-tag */
+        color: #8CD0D3;
+        font-size: 120%;
+        font-weight: bold;
+      }
+      .org-custom-group-tag-1 {
+        /* custom-group-tag-1 */
+        color: #ffc0cb;
+        font-size: 120%;
+        font-weight: bold;
+      }
+      .org-custom-invalid {
+        /* custom-invalid */
+        color: #ffff00;
+        background-color: #ff0000;
+      }
+      .org-custom-link {
+        /* custom-link */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-custom-modified {
+        /* custom-modified */
+        color: #ffffff;
+        background-color: #0000ff;
+      }
+      .org-custom-rogue {
+        /* custom-rogue */
+        color: #ffc0cb;
+        background-color: #000000;
+      }
+      .org-custom-saved {
+        /* custom-saved */
+        text-decoration: underline;
+      }
+      .org-custom-set {
+        /* custom-set */
+        color: #0000ff;
+        background-color: #ffffff;
+      }
+      .org-custom-state {
+        /* custom-state */
+        color: #BFEBBF;
+      }
+      .org-custom-themed {
+        /* custom-themed */
+        color: #ffffff;
+        background-color: #0000ff;
+      }
+      .org-custom-variable-button {
+        /* custom-variable-button */
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-custom-variable-obsolete {
+        /* custom-variable-obsolete */
+        color: #add8e6;
+      }
+      .org-custom-variable-tag {
+        /* custom-variable-tag */
+        color: #8CD0D3;
+        font-weight: bold;
+      }
+      .org-custom-visibility {
+        /* custom-visibility */
+        color: #F0DFAF;
+        font-size: 80%;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-diary {
+        /* diary */
+        color: #ffff00;
+      }
+      .org-diary-anniversary {
+        /* diary-anniversary */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-diary-button {
+      }
+      .org-diary-time {
+        /* diary-time */
+        color: #DFAF8F;
+      }
+      .org-diff-added {
+        /* diff-added */
+        color: #7F9F7F;
+        background-color: #335533;
+      }
+      .org-diff-changed {
+        /* diff-changed */
+        color: #E0CF9F;
+        background-color: #555511;
+      }
+      .org-diff-context {
+      }
+      .org-diff-error {
+        /* diff-error */
+        color: #ff0000;
+        background-color: #000000;
+        font-weight: bold;
+      }
+      .org-diff-file-header {
+        /* diff-file-header */
+        color: #DCDCCC;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-diff-function {
+        /* diff-function */
+        background-color: #5F5F5F;
+      }
+      .org-diff-header {
+        /* diff-header */
+        background-color: #5F5F5F;
+      }
+      .org-diff-hl-change {
+        /* diff-hl-change */
+        color: #8CD0D3;
+        background-color: #6CA0A3;
+      }
+      .org-diff-hl-delete {
+        /* diff-hl-delete */
+        color: #DCA3A3;
+        background-color: #BC8383;
+      }
+      .org-diff-hl-insert {
+        /* diff-hl-insert */
+        color: #8FB28F;
+        background-color: #5F7F5F;
+      }
+      .org-diff-hl-reverted-hunk-highlight {
+      }
+      .org-diff-hunk-header {
+        /* diff-hunk-header */
+        background-color: #5F5F5F;
+      }
+      .org-diff-index {
+        /* diff-index */
+        color: #DCDCCC;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-diff-indicator-added {
+        /* diff-indicator-added */
+        color: #22aa22;
+        background-color: #335533;
+      }
+      .org-diff-indicator-changed {
+        /* diff-indicator-changed */
+        color: #aaaa22;
+        background-color: #555511;
+      }
+      .org-diff-indicator-removed {
+        /* diff-indicator-removed */
+        color: #aa2222;
+        background-color: #553333;
+      }
+      .org-diff-nonexistent {
+        /* diff-nonexistent */
+        color: #DCDCCC;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-diff-refine-added {
+        /* diff-refine-added */
+        color: #BFEBBF;
+        background-color: #338833;
+      }
+      .org-diff-refine-changed {
+        /* diff-refine-changed */
+        color: #F0DFAF;
+        background-color: #888811;
+      }
+      .org-diff-refine-removed {
+        /* diff-refine-removed */
+        color: #CC9393;
+        background-color: #883333;
+      }
+      .org-diff-removed {
+        /* diff-removed */
+        color: #AC7373;
+        background-color: #553333;
+      }
+      .org-dired-async-failures {
+        /* dired-async-failures */
+        color: #CC9393;
+        font-weight: bold;
+      }
+      .org-dired-async-message {
+        /* dired-async-message */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-dired-async-mode-message {
+        /* dired-async-mode-message */
+        color: #F0DFAF;
+      }
+      .org-dired-broken-symlink {
+        /* dired-broken-symlink */
+        color: #ffff00;
+        background-color: #ff0000;
+        font-weight: bold;
+      }
+      .org-dired-directory {
+        /* dired-directory */
+        color: #93E0E3;
+      }
+      .org-dired-flagged {
+        /* dired-flagged */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-dired-header {
+        /* dired-header */
+        color: #7CB8BB;
+      }
+      .org-dired-ignored {
+        /* dired-ignored */
+        color: #b3b3b3;
+      }
+      .org-dired-mark {
+        /* dired-mark */
+        color: #BFEBBF;
+      }
+      .org-dired-marked {
+        /* dired-marked */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-dired-perm-write {
+        /* dired-perm-write */
+        color: #5F7F5F;
+      }
+      .org-dired-set-id {
+        /* dired-set-id */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-dired-special {
+        /* dired-special */
+        color: #DFAF8F;
+      }
+      .org-dired-symlink {
+        /* dired-symlink */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-dired-warning {
+        /* dired-warning */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-doc {
+        /* font-lock-doc-face */
+        color: #9FC59F;
+      }
+      .org-edebug-disabled-breakpoint {
+        /* edebug-disabled-breakpoint */
+        background-color: #335533;
+      }
+      .org-edebug-enabled-breakpoint {
+        /* edebug-enabled-breakpoint */
+        background-color: #383838;
+      }
+      .org-ediff-current-diff-a {
+        /* ediff-current-diff-A */
+        color: #DCDCCC;
+        background-color: #8C5353;
+      }
+      .org-ediff-current-diff-ancestor {
+        /* ediff-current-diff-Ancestor */
+        color: #DCDCCC;
+        background-color: #8C5353;
+      }
+      .org-ediff-current-diff-b {
+        /* ediff-current-diff-B */
+        color: #DCDCCC;
+        background-color: #5F7F5F;
+      }
+      .org-ediff-current-diff-c {
+        /* ediff-current-diff-C */
+        color: #DCDCCC;
+        background-color: #366060;
+      }
+      .org-ediff-even-diff-a {
+        /* ediff-even-diff-A */
+        background-color: #4F4F4F;
+      }
+      .org-ediff-even-diff-ancestor {
+        /* ediff-even-diff-Ancestor */
+        background-color: #4F4F4F;
+      }
+      .org-ediff-even-diff-b {
+        /* ediff-even-diff-B */
+        background-color: #4F4F4F;
+      }
+      .org-ediff-even-diff-c {
+        /* ediff-even-diff-C */
+        background-color: #4F4F4F;
+      }
+      .org-ediff-fine-diff-a {
+        /* ediff-fine-diff-A */
+        color: #DCDCCC;
+        background-color: #AC7373;
+        font-weight: bold;
+      }
+      .org-ediff-fine-diff-ancestor {
+        /* ediff-fine-diff-Ancestor */
+        color: #DCDCCC;
+        background-color: #AC7373;
+      }
+      .org-ediff-fine-diff-b {
+        /* ediff-fine-diff-B */
+        color: #DCDCCC;
+        background-color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-ediff-fine-diff-c {
+        /* ediff-fine-diff-C */
+        color: #DCDCCC;
+        background-color: #5C888B;
+        font-weight: bold;
+      }
+      .org-ediff-odd-diff-a {
+        /* ediff-odd-diff-A */
+        background-color: #5F5F5F;
+      }
+      .org-ediff-odd-diff-ancestor {
+        /* ediff-odd-diff-Ancestor */
+        background-color: #5F5F5F;
+      }
+      .org-ediff-odd-diff-b {
+        /* ediff-odd-diff-B */
+        background-color: #5F5F5F;
+      }
+      .org-ediff-odd-diff-c {
+        /* ediff-odd-diff-C */
+        background-color: #5F5F5F;
+      }
+      .org-eldoc-highlight-function-argument {
+        /* eldoc-highlight-function-argument */
+        font-weight: bold;
+      }
+      .org-elfeed-log-date {
+        /* elfeed-log-date-face */
+        color: #7CB8BB;
+      }
+      .org-elfeed-log-debug-level {
+        /* elfeed-log-debug-level-face */
+        color: #ee00ee;
+      }
+      .org-elfeed-log-error-level {
+        /* elfeed-log-error-level-face */
+        color: #CC9393;
+      }
+      .org-elfeed-log-info-level {
+        /* elfeed-log-info-level-face */
+        color: #8CD0D3;
+      }
+      .org-elfeed-log-warn-level {
+        /* elfeed-log-warn-level-face */
+        color: #F0DFAF;
+      }
+      .org-elfeed-search-date {
+        /* elfeed-search-date-face */
+        color: #E0CF9F;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-elfeed-search-feed {
+        /* elfeed-search-feed-face */
+        color: #93E0E3;
+      }
+      .org-elfeed-search-filter {
+        /* elfeed-search-filter-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-elfeed-search-last-update {
+      }
+      .org-elfeed-search-tag {
+        /* elfeed-search-tag-face */
+        color: #7F9F7F;
+      }
+      .org-elfeed-search-title {
+        /* elfeed-search-title-face */
+        color: #989890;
+      }
+      .org-elfeed-search-unread-count {
+        /* elfeed-search-unread-count-face */
+        color: #fff;
+      }
+      .org-elfeed-search-unread-title {
+        /* elfeed-search-unread-title-face */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-elpy-breakpoint-fringe {
+        /* elpy-breakpoint-fringe-face */
+        color: #ff0000;
+      }
+      .org-epa-field-body {
+        /* epa-field-body */
+        color: #40e0d0;
+        font-style: italic;
+      }
+      .org-epa-field-name {
+        /* epa-field-name */
+        color: #afeeee;
+        font-weight: bold;
+      }
+      .org-epa-mark {
+        /* epa-mark */
+        color: #ffa500;
+        font-weight: bold;
+      }
+      .org-epa-string {
+        /* epa-string */
+        color: #ffffe0;
+      }
+      .org-epa-validity-disabled {
+        /* epa-validity-disabled */
+        font-style: italic;
+      }
+      .org-epa-validity-high {
+        /* epa-validity-high */
+        color: #afeeee;
+        font-weight: bold;
+      }
+      .org-epa-validity-low {
+        /* epa-validity-low */
+        font-style: italic;
+      }
+      .org-epa-validity-medium {
+        /* epa-validity-medium */
+        color: #afeeee;
+        font-style: italic;
+      }
+      .org-erc-action {
+        /* erc-action-face */
+        color: #DCDCCC;
+      }
+      .org-erc-bold {
+        /* erc-bold-face */
+        font-weight: bold;
+      }
+      .org-erc-button {
+        /* erc-button */
+        font-weight: bold;
+      }
+      .org-erc-command-indicator {
+        /* erc-command-indicator-face */
+        font-weight: bold;
+      }
+      .org-erc-current-nick {
+        /* erc-current-nick-face */
+        color: #8CD0D3;
+        font-weight: bold;
+      }
+      .org-erc-dangerous-host {
+        /* erc-dangerous-host-face */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-erc-default {
+        /* erc-default-face */
+        color: #DCDCCC;
+      }
+      .org-erc-direct-msg {
+        /* erc-direct-msg-face */
+        color: #DCDCCC;
+      }
+      .org-erc-error {
+        /* erc-error-face */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-erc-fool {
+        /* erc-fool-face */
+        color: #DCDCCC;
+      }
+      .org-erc-header-line {
+        /* erc-header-line */
+        color: #F0DFAF;
+        background-color: #2B2B2B;
+      }
+      .org-erc-hl-nicks-nick-base {
+      }
+      .org-erc-input {
+        /* erc-input-face */
+        color: #F0DFAF;
+      }
+      .org-erc-inverse {
+        /* erc-inverse-face */
+        color: #ffffff;
+        background-color: #000000;
+      }
+      .org-erc-italic {
+        /* erc-italic-face */
+        font-style: italic;
+      }
+      .org-erc-keyword {
+        /* erc-keyword-face */
+        color: #8CD0D3;
+        font-weight: bold;
+      }
+      .org-erc-my-nick {
+        /* erc-my-nick-face */
+        color: #CC9393;
+        font-weight: bold;
+      }
+      .org-erc-my-nick-prefix {
+        /* erc-my-nick-prefix-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-erc-nick-default {
+        /* erc-nick-default-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-erc-nick-msg {
+        /* erc-nick-msg-face */
+        color: #DCDCCC;
+      }
+      .org-erc-nick-prefix {
+        /* erc-nick-prefix-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-erc-notice {
+        /* erc-notice-face */
+        color: #7F9F7F;
+      }
+      .org-erc-pal {
+        /* erc-pal-face */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-erc-prompt {
+        /* erc-prompt-face */
+        color: #DFAF8F;
+        background-color: #3F3F3F;
+        font-weight: bold;
+      }
+      .org-erc-robot {
+        /* erc-robot-face */
+        color: #483d8b;
+      }
+      .org-erc-timestamp {
+        /* erc-timestamp-face */
+        color: #BFEBBF;
+      }
+      .org-erc-underline {
+        /* erc-underline-face */
+        text-decoration: underline;
+      }
+      .org-error {
+        /* error */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-escape-glyph {
+        /* escape-glyph */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-evil-ex-commands {
+        /* evil-ex-commands */
+        font-style: italic;
+        text-decoration: underline;
+      }
+      .org-evil-ex-info {
+        /* evil-ex-info */
+        color: #ff0000;
+        font-style: italic;
+      }
+      .org-evil-ex-lazy-highlight {
+        /* evil-ex-lazy-highlight */
+        color: #D0BF8F;
+        background-color: #383838;
+        font-weight: bold;
+      }
+      .org-evil-ex-search {
+        /* evil-ex-search */
+        color: #D0BF8F;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-evil-ex-substitute-matches {
+        /* evil-ex-substitute-matches */
+        color: #D0BF8F;
+        background-color: #383838;
+        font-weight: bold;
+      }
+      .org-evil-ex-substitute-replacement {
+        /* evil-ex-substitute-replacement */
+        color: #ff0000;
+        text-decoration: underline;
+      }
+      .org-evil-visual-mark {
+        /* evil-visual-mark-face */
+        color: #ffffff;
+        background-color: #8b008b;
+        text-decoration: underline;
+      }
+      .org-eww-form-checkbox {
+        /* eww-form-checkbox */
+        color: #000000;
+        background-color: #d3d3d3;
+      }
+      .org-eww-form-file {
+        /* eww-form-file */
+        color: #000000;
+        background-color: #808080;
+      }
+      .org-eww-form-select {
+        /* eww-form-select */
+        color: #000000;
+        background-color: #d3d3d3;
+      }
+      .org-eww-form-submit {
+        /* eww-form-submit */
+        color: #000000;
+        background-color: #808080;
+      }
+      .org-eww-form-text {
+        /* eww-form-text */
+        color: #ffffff;
+        background-color: #505050;
+      }
+      .org-eww-form-textarea {
+        /* eww-form-textarea */
+        color: #000000;
+        background-color: #C0C0C0;
+      }
+      .org-eww-invalid-certificate {
+        /* eww-invalid-certificate */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-eww-lnum-number {
+        /* eww-lnum-number */
+        color: #b3b3b3;
+      }
+      .org-eww-valid-certificate {
+        /* eww-valid-certificate */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-excerpt {
+        /* excerpt */
+        font-style: italic;
+      }
+      .org-eyebrowse-mode-line-active {
+        /* eyebrowse-mode-line-active */
+        font-weight: bold;
+      }
+      .org-eyebrowse-mode-line-delimiters {
+      }
+      .org-eyebrowse-mode-line-inactive {
+      }
+      .org-eyebrowse-mode-line-separator {
+      }
+      .org-fancy-battery-charging {
+        /* fancy-battery-charging */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-fancy-battery-critical {
+        /* fancy-battery-critical */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-fancy-battery-discharging {
+        /* fancy-battery-discharging */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-ffap {
+        /* ffap */
+        background-color: #383838;
+      }
+      .org-fgXerc-color-face0 {
+        /* fg:erc-color-face0 */
+        color: #ffffff;
+      }
+      .org-fgXerc-color-face1 {
+        /* fg:erc-color-face1 */
+        color: #000000;
+      }
+      .org-fgXerc-color-face10 {
+        /* fg:erc-color-face10 */
+        color: #bfefff;
+      }
+      .org-fgXerc-color-face11 {
+        /* fg:erc-color-face11 */
+        color: #00ffff;
+      }
+      .org-fgXerc-color-face12 {
+        /* fg:erc-color-face12 */
+        color: #0000ff;
+      }
+      .org-fgXerc-color-face13 {
+        /* fg:erc-color-face13 */
+        color: #ff1493;
+      }
+      .org-fgXerc-color-face14 {
+        /* fg:erc-color-face14 */
+        color: #7f7f7f;
+      }
+      .org-fgXerc-color-face15 {
+        /* fg:erc-color-face15 */
+        color: #e5e5e5;
+      }
+      .org-fgXerc-color-face2 {
+        /* fg:erc-color-face2 */
+        color: #00008b;
+      }
+      .org-fgXerc-color-face3 {
+        /* fg:erc-color-face3 */
+        color: #008b00;
+      }
+      .org-fgXerc-color-face4 {
+        /* fg:erc-color-face4 */
+        color: #ff0000;
+      }
+      .org-fgXerc-color-face5 {
+        /* fg:erc-color-face5 */
+        color: #a52a2a;
+      }
+      .org-fgXerc-color-face6 {
+        /* fg:erc-color-face6 */
+        color: #a020f0;
+      }
+      .org-fgXerc-color-face7 {
+        /* fg:erc-color-face7 */
+        color: #ffa500;
+      }
+      .org-fgXerc-color-face8 {
+        /* fg:erc-color-face8 */
+        color: #ffff00;
+      }
+      .org-fgXerc-color-face9 {
+        /* fg:erc-color-face9 */
+        color: #00ff00;
+      }
+      .org-file-name-shadow {
+        /* file-name-shadow */
+        color: #b3b3b3;
+      }
+      .org-fill-column-indicator {
+        /* fill-column-indicator */
+        color: #383838;
+      }
+      .org-fixed {
+        /* fixed */
+        font-weight: bold;
+      }
+      .org-fixed-pitch {
+      }
+      .org-fixed-pitch-serif {
+      }
+      .org-flx-highlight {
+        /* flx-highlight-face */
+        color: #9FC59F;
+        font-weight: bold;
+      }
+      .org-flycheck-delimited-error {
+      }
+      .org-flycheck-error {
+        /* flycheck-error */
+        text-decoration: underline;
+      }
+      .org-flycheck-error-delimiter {
+      }
+      .org-flycheck-error-list-checker-name {
+        /* flycheck-error-list-checker-name */
+        color: #93E0E3;
+      }
+      .org-flycheck-error-list-column-number {
+      }
+      .org-flycheck-error-list-error {
+        /* flycheck-error-list-error */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-flycheck-error-list-error-message {
+      }
+      .org-flycheck-error-list-filename {
+        /* flycheck-error-list-filename */
+        color: #F0DFAF;
+      }
+      .org-flycheck-error-list-highlight {
+        /* flycheck-error-list-highlight */
+        font-weight: bold;
+      }
+      .org-flycheck-error-list-id {
+        /* flycheck-error-list-id */
+        color: #7CB8BB;
+      }
+      .org-flycheck-error-list-id-with-explainer {
+        /* flycheck-error-list-id-with-explainer */
+        color: #7CB8BB;
+      }
+      .org-flycheck-error-list-info {
+        /* flycheck-error-list-info */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-flycheck-error-list-line-number {
+      }
+      .org-flycheck-error-list-warning {
+        /* flycheck-error-list-warning */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-flycheck-fringe-error {
+        /* flycheck-fringe-error */
+        color: #BC8383;
+        font-weight: bold;
+      }
+      .org-flycheck-fringe-info {
+        /* flycheck-fringe-info */
+        color: #93E0E3;
+        font-weight: bold;
+      }
+      .org-flycheck-fringe-warning {
+        /* flycheck-fringe-warning */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-flycheck-info {
+        /* flycheck-info */
+        text-decoration: underline;
+      }
+      .org-flycheck-verify-select-checker {
+      }
+      .org-flycheck-warning {
+        /* flycheck-warning */
+        text-decoration: underline;
+      }
+      .org-flymake-error {
+        /* flymake-error */
+        text-decoration: underline;
+      }
+      .org-flymake-note {
+        /* flymake-note */
+        text-decoration: underline;
+      }
+      .org-flymake-warning {
+        /* flymake-warning */
+        text-decoration: underline;
+      }
+      .org-flyspell-duplicate {
+        /* flyspell-duplicate */
+        text-decoration: underline;
+      }
+      .org-flyspell-incorrect {
+        /* flyspell-incorrect */
+        text-decoration: underline;
+      }
+      .org-fringe {
+        /* fringe */
+        color: #DCDCCC;
+        background-color: #4F4F4F;
+      }
+      .org-function-name {
+        /* font-lock-function-name-face */
+        color: #93E0E3;
+      }
+      .org-git-commit-comment-action {
+        /* git-commit-comment-action */
+        color: #8FB28F;
+        font-weight: bold;
+      }
+      .org-git-commit-comment-branch-local {
+        /* git-commit-comment-branch-local */
+        color: #94BFF3;
+        font-weight: bold;
+      }
+      .org-git-commit-comment-branch-remote {
+        /* git-commit-comment-branch-remote */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-git-commit-comment-detached {
+        /* git-commit-comment-detached */
+        color: #94BFF3;
+        font-weight: bold;
+      }
+      .org-git-commit-comment-file {
+        /* git-commit-comment-file */
+        color: #CC9393;
+      }
+      .org-git-commit-comment-heading {
+        /* git-commit-comment-heading */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-git-commit-keyword {
+        /* git-commit-keyword */
+        color: #CC9393;
+      }
+      .org-git-commit-known-pseudo-header {
+        /* git-commit-known-pseudo-header */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-git-commit-nonempty-second-line {
+        /* git-commit-nonempty-second-line */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-git-commit-overlong-summary {
+        /* git-commit-overlong-summary */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-git-commit-pseudo-header {
+        /* git-commit-pseudo-header */
+        color: #CC9393;
+      }
+      .org-git-commit-summary {
+        /* git-commit-summary */
+        color: #7CB8BB;
+      }
+      .org-git-rebase-comment-hash {
+        /* git-rebase-comment-hash */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-git-rebase-comment-heading {
+        /* git-rebase-comment-heading */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-git-rebase-description {
+      }
+      .org-git-rebase-hash {
+        /* git-rebase-hash */
+        color: #DFAF8F;
+      }
+      .org-git-rebase-killed-action {
+        /* git-rebase-killed-action */
+        color: #7F9F7F;
+        text-decoration: line-through;
+      }
+      .org-git-rebase-label {
+        /* git-rebase-label */
+        color: #DCDCCC;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-glyphless-char {
+        /* glyphless-char */
+        font-size: 60%;
+      }
+      .org-gnus-button {
+        /* gnus-button */
+        font-weight: bold;
+      }
+      .org-gnus-cite-1 {
+        /* gnus-cite-1 */
+        color: #8CD0D3;
+      }
+      .org-gnus-cite-10 {
+        /* gnus-cite-10 */
+        color: #E0CF9F;
+      }
+      .org-gnus-cite-11 {
+        /* gnus-cite-11 */
+        color: #F0DFAF;
+      }
+      .org-gnus-cite-2 {
+        /* gnus-cite-2 */
+        color: #7CB8BB;
+      }
+      .org-gnus-cite-3 {
+        /* gnus-cite-3 */
+        color: #6CA0A3;
+      }
+      .org-gnus-cite-4 {
+        /* gnus-cite-4 */
+        color: #9FC59F;
+      }
+      .org-gnus-cite-5 {
+        /* gnus-cite-5 */
+        color: #8FB28F;
+      }
+      .org-gnus-cite-6 {
+        /* gnus-cite-6 */
+        color: #7F9F7F;
+      }
+      .org-gnus-cite-7 {
+        /* gnus-cite-7 */
+        color: #CC9393;
+      }
+      .org-gnus-cite-8 {
+        /* gnus-cite-8 */
+        color: #BC8383;
+      }
+      .org-gnus-cite-9 {
+        /* gnus-cite-9 */
+        color: #AC7373;
+      }
+      .org-gnus-cite-attribution {
+        /* gnus-cite-attribution */
+        font-style: italic;
+      }
+      .org-gnus-emphasis-bold {
+        /* gnus-emphasis-bold */
+        font-weight: bold;
+      }
+      .org-gnus-emphasis-bold-italic {
+        /* gnus-emphasis-bold-italic */
+        font-weight: bold;
+        font-style: italic;
+      }
+      .org-gnus-emphasis-highlight-words {
+        /* gnus-emphasis-highlight-words */
+        color: #ffff00;
+        background-color: #000000;
+      }
+      .org-gnus-emphasis-italic {
+        /* gnus-emphasis-italic */
+        font-style: italic;
+      }
+      .org-gnus-emphasis-strikethru {
+        /* gnus-emphasis-strikethru */
+        text-decoration: line-through;
+      }
+      .org-gnus-emphasis-underline {
+        /* gnus-emphasis-underline */
+        text-decoration: underline;
+      }
+      .org-gnus-emphasis-underline-bold {
+        /* gnus-emphasis-underline-bold */
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-gnus-emphasis-underline-bold-italic {
+        /* gnus-emphasis-underline-bold-italic */
+        font-weight: bold;
+        font-style: italic;
+        text-decoration: underline;
+      }
+      .org-gnus-emphasis-underline-italic {
+        /* gnus-emphasis-underline-italic */
+        font-style: italic;
+        text-decoration: underline;
+      }
+      .org-gnus-group-mail-1 {
+        /* gnus-group-mail-1 */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-gnus-group-mail-1-empty {
+        /* gnus-group-mail-1-empty */
+        color: #F0DFAF;
+      }
+      .org-gnus-group-mail-2 {
+        /* gnus-group-mail-2 */
+        color: #AFD8AF;
+        font-weight: bold;
+      }
+      .org-gnus-group-mail-2-empty {
+        /* gnus-group-mail-2-empty */
+        color: #AFD8AF;
+      }
+      .org-gnus-group-mail-3 {
+        /* gnus-group-mail-3 */
+        color: #8FB28F;
+        font-weight: bold;
+      }
+      .org-gnus-group-mail-3-empty {
+        /* gnus-group-mail-3-empty */
+        color: #8FB28F;
+      }
+      .org-gnus-group-mail-low {
+        /* gnus-group-mail-low */
+        color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-gnus-group-mail-low-empty {
+        /* gnus-group-mail-low-empty */
+        color: #5F5F5F;
+      }
+      .org-gnus-group-news-1 {
+        /* gnus-group-news-1 */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-gnus-group-news-1-empty {
+        /* gnus-group-news-1-empty */
+        color: #F0DFAF;
+      }
+      .org-gnus-group-news-2 {
+        /* gnus-group-news-2 */
+        color: #AFD8AF;
+        font-weight: bold;
+      }
+      .org-gnus-group-news-2-empty {
+        /* gnus-group-news-2-empty */
+        color: #AFD8AF;
+      }
+      .org-gnus-group-news-3 {
+        /* gnus-group-news-3 */
+        color: #8FB28F;
+        font-weight: bold;
+      }
+      .org-gnus-group-news-3-empty {
+        /* gnus-group-news-3-empty */
+        color: #8FB28F;
+      }
+      .org-gnus-group-news-4 {
+        /* gnus-group-news-4 */
+        color: #6CA0A3;
+        font-weight: bold;
+      }
+      .org-gnus-group-news-4-empty {
+        /* gnus-group-news-4-empty */
+        color: #6CA0A3;
+      }
+      .org-gnus-group-news-5 {
+        /* gnus-group-news-5 */
+        color: #5C888B;
+        font-weight: bold;
+      }
+      .org-gnus-group-news-5-empty {
+        /* gnus-group-news-5-empty */
+        color: #5C888B;
+      }
+      .org-gnus-group-news-6 {
+        /* gnus-group-news-6 */
+        color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-gnus-group-news-6-empty {
+        /* gnus-group-news-6-empty */
+        color: #5F5F5F;
+      }
+      .org-gnus-group-news-low {
+        /* gnus-group-news-low */
+        color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-gnus-group-news-low-empty {
+        /* gnus-group-news-low-empty */
+        color: #5F5F5F;
+      }
+      .org-gnus-header-content {
+        /* gnus-header-content */
+        color: #7F9F7F;
+      }
+      .org-gnus-header-from {
+        /* gnus-header-from */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-gnus-header-name {
+        /* gnus-header-name */
+        color: #8FB28F;
+      }
+      .org-gnus-header-newsgroups {
+        /* gnus-header-newsgroups */
+        color: #7F9F7F;
+      }
+      .org-gnus-header-subject {
+        /* gnus-header-subject */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-gnus-server-agent {
+        /* gnus-server-agent */
+        color: #8CD0D3;
+        font-weight: bold;
+      }
+      .org-gnus-server-closed {
+        /* gnus-server-closed */
+        color: #8CD0D3;
+        font-style: italic;
+      }
+      .org-gnus-server-cloud {
+        /* gnus-server-cloud */
+        color: #98fb98;
+        font-weight: bold;
+      }
+      .org-gnus-server-cloud-host {
+        /* gnus-server-cloud-host */
+        color: #98fb98;
+        font-style: italic;
+      }
+      .org-gnus-server-denied {
+        /* gnus-server-denied */
+        color: #DCA3A3;
+        font-weight: bold;
+      }
+      .org-gnus-server-offline {
+        /* gnus-server-offline */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-gnus-server-opened {
+        /* gnus-server-opened */
+        color: #9FC59F;
+        font-weight: bold;
+      }
+      .org-gnus-signature {
+        /* gnus-signature */
+        color: #F0DFAF;
+      }
+      .org-gnus-splash {
+        /* gnus-splash */
+        color: #cccccc;
+      }
+      .org-gnus-summary-cancelled {
+        /* gnus-summary-cancelled */
+        color: #DFAF8F;
+      }
+      .org-gnus-summary-high-ancient {
+        /* gnus-summary-high-ancient */
+        color: #8CD0D3;
+      }
+      .org-gnus-summary-high-read {
+        /* gnus-summary-high-read */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-gnus-summary-high-ticked {
+        /* gnus-summary-high-ticked */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-gnus-summary-high-undownloaded {
+        /* gnus-summary-high-undownloaded */
+        color: #008b8b;
+        font-weight: bold;
+      }
+      .org-gnus-summary-high-unread {
+        /* gnus-summary-high-unread */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-gnus-summary-low-ancient {
+        /* gnus-summary-low-ancient */
+        color: #8CD0D3;
+      }
+      .org-gnus-summary-low-read {
+        /* gnus-summary-low-read */
+        color: #7F9F7F;
+      }
+      .org-gnus-summary-low-ticked {
+        /* gnus-summary-low-ticked */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-gnus-summary-low-undownloaded {
+        /* gnus-summary-low-undownloaded */
+        color: #008b8b;
+        font-style: italic;
+      }
+      .org-gnus-summary-low-unread {
+        /* gnus-summary-low-unread */
+        color: #DCDCCC;
+      }
+      .org-gnus-summary-normal-ancient {
+        /* gnus-summary-normal-ancient */
+        color: #8CD0D3;
+      }
+      .org-gnus-summary-normal-read {
+        /* gnus-summary-normal-read */
+        color: #7F9F7F;
+      }
+      .org-gnus-summary-normal-ticked {
+        /* gnus-summary-normal-ticked */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-gnus-summary-normal-undownloaded {
+        /* gnus-summary-normal-undownloaded */
+        color: #008b8b;
+      }
+      .org-gnus-summary-normal-unread {
+        /* gnus-summary-normal-unread */
+        color: #DCDCCC;
+      }
+      .org-gnus-summary-selected {
+        /* gnus-summary-selected */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-header-line {
+        /* header-line */
+        color: #F0DFAF;
+        background-color: #2B2B2B;
+      }
+      .org-header-line-highlight {
+      }
+      .org-helm-action {
+        /* helm-action */
+        text-decoration: underline;
+      }
+      .org-helm-buffer-archive {
+        /* helm-buffer-archive */
+        color: #ffd700;
+      }
+      .org-helm-buffer-directory {
+        /* helm-buffer-directory */
+        color: #8b0000;
+        background-color: #d3d3d3;
+      }
+      .org-helm-buffer-file {
+        /* helm-buffer-file */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-helm-buffer-modified {
+        /* helm-buffer-modified */
+        color: #7F9F7F;
+      }
+      .org-helm-buffer-not-saved {
+        /* helm-buffer-not-saved */
+        color: #CC9393;
+        background-color: #3F3F3F;
+      }
+      .org-helm-buffer-process {
+        /* helm-buffer-process */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+      }
+      .org-helm-buffer-saved-out {
+        /* helm-buffer-saved-out */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-helm-buffer-size {
+        /* helm-buffer-size */
+        color: #656555;
+        background-color: #3F3F3F;
+      }
+      .org-helm-candidate-number {
+        /* helm-candidate-number */
+        color: #BFEBBF;
+        background-color: #2B2B2B;
+      }
+      .org-helm-candidate-number-suspended {
+        /* helm-candidate-number-suspended */
+        color: #BFEBBF;
+        background-color: #2B2B2B;
+      }
+      .org-helm-delete-async-message {
+        /* helm-delete-async-message */
+        color: #ffff00;
+      }
+      .org-helm-eob-line {
+        /* helm-eob-line */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-helm-etags-file {
+        /* helm-etags-file */
+        color: #8b814c;
+        text-decoration: underline;
+      }
+      .org-helm-ff-backup-file {
+        /* helm-ff-backup-file */
+        color: #696969;
+      }
+      .org-helm-ff-denied {
+        /* helm-ff-denied */
+        color: #ff0000;
+        background-color: #000000;
+      }
+      .org-helm-ff-directory {
+        /* helm-ff-directory */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+        font-weight: bold;
+      }
+      .org-helm-ff-dirs {
+        /* helm-ff-dirs */
+        color: #93E0E3;
+      }
+      .org-helm-ff-dotted-directory {
+        /* helm-ff-dotted-directory */
+        color: #000000;
+        background-color: #696969;
+      }
+      .org-helm-ff-dotted-symlink-directory {
+        /* helm-ff-dotted-symlink-directory */
+        color: #ff8c00;
+        background-color: #696969;
+      }
+      .org-helm-ff-executable {
+        /* helm-ff-executable */
+        color: #9FC59F;
+        background-color: #3F3F3F;
+      }
+      .org-helm-ff-file {
+        /* helm-ff-file */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-helm-ff-file-extension {
+        /* helm-ff-file-extension */
+        color: #ff00ff;
+      }
+      .org-helm-ff-invalid-symlink {
+        /* helm-ff-invalid-symlink */
+        color: #CC9393;
+        background-color: #3F3F3F;
+        font-weight: bold;
+      }
+      .org-helm-ff-pipe {
+        /* helm-ff-pipe */
+        color: #ffff00;
+        background-color: #000000;
+      }
+      .org-helm-ff-prefix {
+        /* helm-ff-prefix */
+        color: #3F3F3F;
+        background-color: #F0DFAF;
+      }
+      .org-helm-ff-rsync-progress {
+        /* helm-ff-rsync-progress */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-helm-ff-socket {
+        /* helm-ff-socket */
+        color: #ff1493;
+      }
+      .org-helm-ff-suid {
+        /* helm-ff-suid */
+        color: #ffffff;
+        background-color: #ff0000;
+      }
+      .org-helm-ff-symlink {
+        /* helm-ff-symlink */
+        color: #F0DFAF;
+        background-color: #3F3F3F;
+        font-weight: bold;
+      }
+      .org-helm-ff-truename {
+        /* helm-ff-truename */
+        color: #CC9393;
+      }
+      .org-helm-grep-cmd-line {
+        /* helm-grep-cmd-line */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+      }
+      .org-helm-grep-file {
+        /* helm-grep-file */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-helm-grep-finish {
+        /* helm-grep-finish */
+        color: #9FC59F;
+        background-color: #3F3F3F;
+      }
+      .org-helm-grep-lineno {
+        /* helm-grep-lineno */
+        color: #656555;
+        background-color: #3F3F3F;
+      }
+      .org-helm-grep-match {
+        /* helm-grep-match */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-helm-header {
+        /* helm-header */
+        color: #7F9F7F;
+        background-color: #3F3F3F;
+      }
+      .org-helm-header-line-left-margin {
+        /* helm-header-line-left-margin */
+        color: #000000;
+        background-color: #ffff00;
+      }
+      .org-helm-helper {
+        /* helm-helper */
+        color: #7F9F7F;
+        background-color: #3F3F3F;
+      }
+      .org-helm-history-deleted {
+        /* helm-history-deleted */
+        color: #CC9393;
+        background-color: #3F3F3F;
+        font-weight: bold;
+      }
+      .org-helm-history-remote {
+        /* helm-history-remote */
+        color: #ff6a6a;
+      }
+      .org-helm-lisp-completion-info {
+        /* helm-lisp-completion-info */
+        color: #ff0000;
+      }
+      .org-helm-lisp-show-completion {
+        /* helm-lisp-show-completion */
+        background-color: #2f4f4f;
+      }
+      .org-helm-locate-finish {
+        /* helm-locate-finish */
+        color: #00ff00;
+      }
+      .org-helm-match {
+        /* helm-match */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-helm-match-item {
+        /* helm-match-item */
+        color: #D0BF8F;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-helm-minibuffer-prompt {
+        /* helm-minibuffer-prompt */
+        color: #F0DFAF;
+      }
+      .org-helm-moccur-buffer {
+        /* helm-moccur-buffer */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+      }
+      .org-helm-mode-prefix {
+      }
+      .org-helm-non-file-buffer {
+        /* helm-non-file-buffer */
+        font-style: italic;
+      }
+      .org-helm-prefarg {
+        /* helm-prefarg */
+        color: #00ff00;
+      }
+      .org-helm-resume-need-update {
+        /* helm-resume-need-update */
+        background-color: #ff0000;
+      }
+      .org-helm-selection {
+        /* helm-selection */
+        background-color: #4F4F4F;
+      }
+      .org-helm-selection-line {
+        /* helm-selection-line */
+        background-color: #4F4F4F;
+      }
+      .org-helm-separator {
+        /* helm-separator */
+        color: #CC9393;
+        background-color: #3F3F3F;
+      }
+      .org-helm-source-header {
+        /* helm-source-header */
+        color: #F0DFAF;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-helm-time-zone-current {
+        /* helm-time-zone-current */
+        color: #9FC59F;
+        background-color: #3F3F3F;
+      }
+      .org-helm-time-zone-home {
+        /* helm-time-zone-home */
+        color: #CC9393;
+        background-color: #3F3F3F;
+      }
+      .org-helm-visible-mark {
+        /* helm-visible-mark */
+        color: #3F3F3F;
+        background-color: #D0BF8F;
+      }
+      .org-help-argument-name {
+        /* help-argument-name */
+        font-style: italic;
+      }
+      .org-help-key-binding {
+        /* help-key-binding */
+        color: #add8e6;
+        background-color: #303030;
+      }
+      .org-hi-aquamarine {
+        /* hi-aquamarine */
+        color: #000000;
+        background-color: #7fffd4;
+      }
+      .org-hi-black-b {
+        /* hi-black-b */
+        font-weight: bold;
+      }
+      .org-hi-black-hb {
+        /* hi-black-hb */
+        font-size: 167%;
+        font-weight: bold;
+      }
+      .org-hi-blue {
+        /* hi-blue */
+        color: #2B2B2B;
+        background-color: #93E0E3;
+      }
+      .org-hi-blue-b {
+        /* hi-blue-b */
+        color: #8CD0D3;
+        font-weight: bold;
+      }
+      .org-hi-green {
+        /* hi-green */
+        color: #2B2B2B;
+        background-color: #BFEBBF;
+      }
+      .org-hi-green-b {
+        /* hi-green-b */
+        color: #9FC59F;
+        font-weight: bold;
+      }
+      .org-hi-pink {
+        /* hi-pink */
+        color: #2B2B2B;
+        background-color: #DC8CC3;
+      }
+      .org-hi-red-b {
+        /* hi-red-b */
+        color: #CC9393;
+        font-weight: bold;
+      }
+      .org-hi-salmon {
+        /* hi-salmon */
+        color: #000000;
+        background-color: #ffa07a;
+      }
+      .org-hi-yellow {
+        /* hi-yellow */
+        color: #2B2B2B;
+        background-color: #F0DFAF;
+      }
+      .org-highlight {
+        /* highlight */
+        background-color: #383838;
+      }
+      .org-hl-line {
+        /* hl-line */
+        background-color: #383838;
+      }
+      .org-hl-todo {
+        /* hl-todo */
+        color: #cc9393;
+        font-weight: bold;
+      }
+      .org-holiday {
+        /* holiday */
+        background-color: #8b4513;
+      }
+      .org-homoglyph {
+        /* homoglyph */
+        color: #00ffff;
+      }
+      .org-hydra-face-amaranth {
+        /* hydra-face-amaranth */
+        color: #9C6363;
+        background-color: #3F3F3F;
+      }
+      .org-hydra-face-blue {
+        /* hydra-face-blue */
+        color: #8CD0D3;
+        background-color: #3F3F3F;
+      }
+      .org-hydra-face-pink {
+        /* hydra-face-pink */
+        color: #DC8CC3;
+        background-color: #3F3F3F;
+      }
+      .org-hydra-face-red {
+        /* hydra-face-red */
+        color: #BC8383;
+        background-color: #3F3F3F;
+      }
+      .org-hydra-face-teal {
+        /* hydra-face-teal */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+      }
+      .org-ibuffer-locked-buffer {
+        /* ibuffer-locked-buffer */
+        color: #bc8f8f;
+      }
+      .org-icomplete-first-match {
+        /* icomplete-first-match */
+        font-weight: bold;
+      }
+      .org-idle-highlight {
+        /* idle-highlight */
+        background-color: #2B2B2B;
+      }
+      .org-ido-first-match {
+        /* ido-first-match */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-ido-incomplete-regexp {
+        /* ido-incomplete-regexp */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-ido-indicator {
+        /* ido-indicator */
+        color: #F0DFAF;
+        background-color: #8C5353;
+      }
+      .org-ido-only-match {
+        /* ido-only-match */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-ido-subdir {
+        /* ido-subdir */
+        color: #F0DFAF;
+      }
+      .org-ido-vertical-first-match {
+        /* ido-vertical-first-match-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-ido-vertical-match {
+        /* ido-vertical-match-face */
+        color: #DFAF8F;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-ido-vertical-only-match {
+        /* ido-vertical-only-match-face */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-ido-virtual {
+        /* ido-virtual */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-iedit-occurrence {
+        /* iedit-occurrence */
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-iedit-read-only-occurrence {
+        /* iedit-read-only-occurrence */
+        background-color: #2B2B2B;
+      }
+      .org-info-header-node {
+        /* info-header-node */
+        color: #ffffff;
+        font-weight: bold;
+        font-style: italic;
+      }
+      .org-info-header-xref {
+        /* info-header-xref */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-info-index-match {
+        /* info-index-match */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-info-menu-header {
+        /* info-menu-header */
+        font-weight: bold;
+      }
+      .org-info-menu-star {
+        /* info-menu-star */
+        color: #ff0000;
+      }
+      .org-info-node {
+        /* info-node */
+        color: #ffffff;
+        font-weight: bold;
+        font-style: italic;
+      }
+      .org-info-quoted {
+        /* Info-quoted */
+        color: #BFEBBF;
+      }
+      .org-info-title-1 {
+        /* info-title-1 */
+        font-size: 172%;
+        font-weight: bold;
+      }
+      .org-info-title-2 {
+        /* info-title-2 */
+        font-size: 144%;
+        font-weight: bold;
+      }
+      .org-info-title-3 {
+        /* info-title-3 */
+        font-size: 120%;
+        font-weight: bold;
+      }
+      .org-info-title-4 {
+        /* info-title-4 */
+        font-weight: bold;
+      }
+      .org-info-xref {
+        /* info-xref */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-internal-border {
+      }
+      .org-isearch {
+        /* isearch */
+        color: #D0BF8F;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-isearch-fail {
+        /* isearch-fail */
+        color: #DCDCCC;
+        background-color: #8C5353;
+      }
+      .org-isearch-group-1 {
+        /* isearch-group-1 */
+        color: #8b2323;
+        background-color: #ff82ab;
+      }
+      .org-isearch-group-2 {
+        /* isearch-group-2 */
+        color: #8b2323;
+        background-color: #cd6889;
+      }
+      .org-italic {
+        /* italic */
+        font-style: italic;
+      }
+      .org-ivy-action {
+        /* ivy-action */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-ivy-completions-annotations {
+        /* ivy-completions-annotations */
+        color: #656555;
+      }
+      .org-ivy-confirm {
+        /* ivy-confirm-face */
+        color: #7F9F7F;
+        background-color: #3F3F3F;
+      }
+      .org-ivy-current-match {
+        /* ivy-current-match */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-ivy-cursor {
+        /* ivy-cursor */
+        color: #3F3F3F;
+        background-color: #DCDCCC;
+      }
+      .org-ivy-grep-info {
+        /* ivy-grep-info */
+        color: #BFEBBF;
+        text-decoration: underline;
+      }
+      .org-ivy-grep-line-number {
+        /* ivy-grep-line-number */
+        color: #F0DFAF;
+      }
+      .org-ivy-highlight {
+        /* ivy-highlight-face */
+        background-color: #383838;
+      }
+      .org-ivy-match-required {
+        /* ivy-match-required-face */
+        color: #CC9393;
+        background-color: #3F3F3F;
+      }
+      .org-ivy-minibuffer-match-face-1 {
+        /* ivy-minibuffer-match-face-1 */
+        background-color: #4F4F4F;
+      }
+      .org-ivy-minibuffer-match-face-2 {
+        /* ivy-minibuffer-match-face-2 */
+        background-color: #5F7F5F;
+      }
+      .org-ivy-minibuffer-match-face-3 {
+        /* ivy-minibuffer-match-face-3 */
+        background-color: #7F9F7F;
+      }
+      .org-ivy-minibuffer-match-face-4 {
+        /* ivy-minibuffer-match-face-4 */
+        background-color: #8FB28F;
+      }
+      .org-ivy-minibuffer-match-highlight {
+        /* ivy-minibuffer-match-highlight */
+        background-color: #383838;
+      }
+      .org-ivy-modified-buffer {
+        /* ivy-modified-buffer */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-ivy-modified-outside-buffer {
+        /* ivy-modified-outside-buffer */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-ivy-org {
+        /* ivy-org */
+        color: #D0BF8F;
+        background-color: #3F3F3F;
+      }
+      .org-ivy-prompt-match {
+        /* ivy-prompt-match */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-ivy-remote {
+        /* ivy-remote */
+        color: #8CD0D3;
+        background-color: #3F3F3F;
+      }
+      .org-ivy-separator {
+        /* ivy-separator */
+        color: #9FC59F;
+      }
+      .org-ivy-subdir {
+        /* ivy-subdir */
+        color: #F0DFAF;
+        background-color: #3F3F3F;
+      }
+      .org-ivy-virtual {
+        /* ivy-virtual */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-ivy-yanked-word {
+        /* ivy-yanked-word */
+        background-color: #383838;
+      }
+      .org-keyword {
+        /* font-lock-keyword-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-kill-ring-ido-number {
+        /* kill-ring-ido-number-face */
+        color: #000000;
+        background-color: #cccccc;
+      }
+      .org-lazy-highlight {
+        /* lazy-highlight */
+        color: #D0BF8F;
+        background-color: #383838;
+        font-weight: bold;
+      }
+      .org-line-number {
+        /* line-number */
+        color: #6F6F6F;
+        background-color: #383838;
+      }
+      .org-line-number-current-line {
+        /* line-number-current-line */
+        color: #D0BF8F;
+        background-color: #383838;
+      }
+      .org-line-number-major-tick {
+        /* line-number-major-tick */
+        background-color: #bfbfbf;
+        font-weight: bold;
+      }
+      .org-line-number-minor-tick {
+        /* line-number-minor-tick */
+        background-color: #8c8c8c;
+        font-weight: bold;
+      }
+      .org-link {
+        /* link */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-link-visited {
+        /* link-visited */
+        color: #D0BF8F;
+        text-decoration: underline;
+      }
+      .org-log-edit-header {
+        /* log-edit-header */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-log-edit-summary {
+        /* log-edit-summary */
+        color: #93E0E3;
+      }
+      .org-log-edit-unknown-header {
+        /* log-edit-unknown-header */
+        color: #7F9F7F;
+      }
+      .org-log-view-commit-body {
+        /* log-view-commit-body */
+        color: #7F9F7F;
+      }
+      .org-log-view-file {
+        /* log-view-file */
+        font-weight: bold;
+      }
+      .org-log-view-message {
+        /* log-view-message */
+        font-weight: bold;
+      }
+      .org-lsp-details {
+        /* lsp-details-face */
+        color: #b3b3b3;
+        font-size: 80%;
+      }
+      .org-lsp-face-highlight-read {
+        /* lsp-face-highlight-read */
+        background-color: #383838;
+        text-decoration: underline;
+      }
+      .org-lsp-face-highlight-textual {
+        /* lsp-face-highlight-textual */
+        background-color: #383838;
+      }
+      .org-lsp-face-highlight-write {
+        /* lsp-face-highlight-write */
+        background-color: #383838;
+        font-weight: bold;
+      }
+      .org-lsp-face-rename {
+        /* lsp-face-rename */
+        text-decoration: underline;
+      }
+      .org-lsp-installation-buffer {
+        /* lsp-installation-buffer-face */
+        color: #00ff00;
+      }
+      .org-lsp-installation-finished-buffer {
+        /* lsp-installation-finished-buffer-face */
+        color: #ffa500;
+      }
+      .org-lsp-rename-placeholder {
+        /* lsp-rename-placeholder-face */
+        color: #DFAF8F;
+      }
+      .org-lsp-signature {
+        /* lsp-signature-face */
+        color: #b3b3b3;
+        font-size: 80%;
+      }
+      .org-lsp-signature-posframe {
+        /* lsp-signature-posframe */
+        color: #DCDCCC;
+        background-color: #4F4F4F;
+      }
+      .org-lsp-treemacs-file-error {
+        /* lsp-treemacs-file-error */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-lsp-treemacs-file-hint {
+        /* lsp-treemacs-file-hint */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-lsp-treemacs-file-info {
+        /* lsp-treemacs-file-info */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-lsp-treemacs-file-warn {
+        /* lsp-treemacs-file-warn */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-lsp-treemacs-project-root-error {
+        /* lsp-treemacs-project-root-error */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-lsp-treemacs-project-root-info {
+        /* lsp-treemacs-project-root-info */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-lsp-treemacs-project-root-warn {
+        /* lsp-treemacs-project-root-warn */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-lsp-ui-doc-background {
+        /* lsp-ui-doc-background */
+        background-color: #272A36;
+      }
+      .org-lsp-ui-doc-header {
+        /* lsp-ui-doc-header */
+        color: #000000;
+        background-color: #00bfff;
+      }
+      .org-lsp-ui-doc-highlight-hover {
+        /* lsp-ui-doc-highlight-hover */
+        background-color: #2B2B2B;
+      }
+      .org-lsp-ui-doc-url {
+        /* lsp-ui-doc-url */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-lsp-ui-peek-filename {
+        /* lsp-ui-peek-filename */
+        color: #ff8c00;
+      }
+      .org-lsp-ui-peek-footer {
+        /* lsp-ui-peek-footer */
+        color: #000000;
+        background-color: #ffffff;
+      }
+      .org-lsp-ui-peek-header {
+        /* lsp-ui-peek-header */
+        color: #000000;
+        background-color: #ffffff;
+      }
+      .org-lsp-ui-peek-highlight {
+        /* lsp-ui-peek-highlight */
+        color: #000000;
+        background-color: #ffffff;
+      }
+      .org-lsp-ui-peek-line-number {
+        /* lsp-ui-peek-line-number */
+        color: #404040;
+      }
+      .org-lsp-ui-peek-list {
+        /* lsp-ui-peek-list */
+        background-color: #181818;
+      }
+      .org-lsp-ui-peek-peek {
+        /* lsp-ui-peek-peek */
+        background-color: #031A25;
+      }
+      .org-lsp-ui-peek-selection {
+        /* lsp-ui-peek-selection */
+        color: #000000;
+        background-color: #ffffff;
+      }
+      .org-lsp-ui-sideline-code-action {
+        /* lsp-ui-sideline-code-action */
+        color: #ffff00;
+      }
+      .org-lsp-ui-sideline-current-symbol {
+        /* lsp-ui-sideline-current-symbol */
+        color: #ffffff;
+        font-size: 99%;
+      }
+      .org-lsp-ui-sideline-global {
+      }
+      .org-lsp-ui-sideline-symbol {
+        /* lsp-ui-sideline-symbol */
+        color: #bebebe;
+        font-size: 99%;
+      }
+      .org-lsp-ui-sideline-symbol-info {
+        /* lsp-ui-sideline-symbol-info */
+        font-size: 99%;
+        font-style: italic;
+      }
+      .org-lv-separator {
+        /* lv-separator */
+        background-color: #4d4d4d;
+      }
+      .org-macrostep-compiler-macro {
+        /* macrostep-compiler-macro-face */
+        font-style: italic;
+      }
+      .org-macrostep-expansion-highlight {
+        /* macrostep-expansion-highlight-face */
+        background-color: #383838;
+      }
+      .org-macrostep-gensym-1 {
+        /* macrostep-gensym-1 */
+        color: #9FC59F;
+        background-color: #2B2B2B;
+      }
+      .org-macrostep-gensym-2 {
+        /* macrostep-gensym-2 */
+        color: #DCA3A3;
+        background-color: #2B2B2B;
+      }
+      .org-macrostep-gensym-3 {
+        /* macrostep-gensym-3 */
+        color: #94BFF3;
+        background-color: #2B2B2B;
+      }
+      .org-macrostep-gensym-4 {
+        /* macrostep-gensym-4 */
+        color: #DC8CC3;
+        background-color: #2B2B2B;
+      }
+      .org-macrostep-gensym-5 {
+        /* macrostep-gensym-5 */
+        color: #F0DFAF;
+        background-color: #2B2B2B;
+      }
+      .org-macrostep-macro {
+        /* macrostep-macro-face */
+        text-decoration: underline;
+      }
+      .org-magit-bisect-bad {
+        /* magit-bisect-bad */
+        color: #CC9393;
+      }
+      .org-magit-bisect-good {
+        /* magit-bisect-good */
+        color: #7F9F7F;
+      }
+      .org-magit-bisect-skip {
+        /* magit-bisect-skip */
+        color: #F0DFAF;
+      }
+      .org-magit-blame-date {
+        /* magit-blame-date */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+      }
+      .org-magit-blame-dimmed {
+        /* magit-blame-dimmed */
+        color: #6F6F6F;
+      }
+      .org-magit-blame-hash {
+        /* magit-blame-hash */
+        color: #6CA0A3;
+        background-color: #2B2B2B;
+      }
+      .org-magit-blame-heading {
+        /* magit-blame-heading */
+        color: #6CA0A3;
+        background-color: #2B2B2B;
+      }
+      .org-magit-blame-highlight {
+        /* magit-blame-highlight */
+        color: #ffffff;
+        background-color: #404040;
+      }
+      .org-magit-blame-margin {
+        /* magit-blame-margin */
+        color: #ffffff;
+        background-color: #404040;
+      }
+      .org-magit-blame-name {
+        /* magit-blame-name */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+      }
+      .org-magit-blame-summary {
+        /* magit-blame-summary */
+        color: #6CA0A3;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-magit-branch-current {
+        /* magit-branch-current */
+        color: #8CD0D3;
+        font-weight: bold;
+      }
+      .org-magit-branch-local {
+        /* magit-branch-local */
+        color: #8CD0D3;
+        font-weight: bold;
+      }
+      .org-magit-branch-remote {
+        /* magit-branch-remote */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-magit-branch-remote-head {
+        /* magit-branch-remote-head */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-magit-branch-upstream {
+        /* magit-branch-upstream */
+        font-style: italic;
+      }
+      .org-magit-cherry-equivalent {
+        /* magit-cherry-equivalent */
+        color: #DC8CC3;
+      }
+      .org-magit-cherry-unmatched {
+        /* magit-cherry-unmatched */
+        color: #93E0E3;
+      }
+      .org-magit-diff-added {
+        /* magit-diff-added */
+        background-color: #5F7F5F;
+      }
+      .org-magit-diff-added-highlight {
+        /* magit-diff-added-highlight */
+        background-color: #7F9F7F;
+      }
+      .org-magit-diff-base {
+        /* magit-diff-base */
+        color: #ffffcc;
+        background-color: #555522;
+      }
+      .org-magit-diff-base-highlight {
+        /* magit-diff-base-highlight */
+        color: #eeeebb;
+        background-color: #666622;
+      }
+      .org-magit-diff-conflict-heading {
+        /* magit-diff-conflict-heading */
+        background-color: #4F4F4F;
+      }
+      .org-magit-diff-context {
+        /* magit-diff-context */
+        color: #b3b3b3;
+      }
+      .org-magit-diff-context-highlight {
+        /* magit-diff-context-highlight */
+        color: #b3b3b3;
+        background-color: #494949;
+      }
+      .org-magit-diff-file-heading {
+        /* magit-diff-file-heading */
+        font-weight: bold;
+      }
+      .org-magit-diff-file-heading-highlight {
+        /* magit-diff-file-heading-highlight */
+        background-color: #494949;
+        font-weight: bold;
+      }
+      .org-magit-diff-file-heading-selection {
+        /* magit-diff-file-heading-selection */
+        color: #DFAF8F;
+        background-color: #494949;
+        font-weight: bold;
+      }
+      .org-magit-diff-hunk-heading {
+        /* magit-diff-hunk-heading */
+        background-color: #4F4F4F;
+      }
+      .org-magit-diff-hunk-heading-highlight {
+        /* magit-diff-hunk-heading-highlight */
+        background-color: #5F5F5F;
+      }
+      .org-magit-diff-hunk-heading-selection {
+        /* magit-diff-hunk-heading-selection */
+        color: #DFAF8F;
+        background-color: #5F5F5F;
+      }
+      .org-magit-diff-hunk-region {
+        /* magit-diff-hunk-region */
+        font-weight: bold;
+      }
+      .org-magit-diff-lines-boundary {
+        /* magit-diff-lines-boundary */
+        color: #5F5F5F;
+        background-color: #DFAF8F;
+      }
+      .org-magit-diff-lines-heading {
+        /* magit-diff-lines-heading */
+        color: #5F5F5F;
+        background-color: #DFAF8F;
+      }
+      .org-magit-diff-our {
+        /* magit-diff-our */
+        background-color: #8C5353;
+      }
+      .org-magit-diff-our-highlight {
+        /* magit-diff-our-highlight */
+        background-color: #9C6363;
+      }
+      .org-magit-diff-removed {
+        /* magit-diff-removed */
+        background-color: #8C5353;
+      }
+      .org-magit-diff-removed-highlight {
+        /* magit-diff-removed-highlight */
+        background-color: #9C6363;
+      }
+      .org-magit-diff-revision-summary {
+        /* magit-diff-revision-summary */
+        background-color: #4F4F4F;
+      }
+      .org-magit-diff-revision-summary-highlight {
+        /* magit-diff-revision-summary-highlight */
+        background-color: #5F5F5F;
+      }
+      .org-magit-diff-their {
+        /* magit-diff-their */
+        background-color: #5F7F5F;
+      }
+      .org-magit-diff-their-highlight {
+        /* magit-diff-their-highlight */
+        background-color: #7F9F7F;
+      }
+      .org-magit-diff-whitespace-warning {
+        /* magit-diff-whitespace-warning */
+        background-color: #CC9393;
+      }
+      .org-magit-diffstat-added {
+        /* magit-diffstat-added */
+        color: #BFEBBF;
+      }
+      .org-magit-diffstat-removed {
+        /* magit-diffstat-removed */
+        color: #CC9393;
+      }
+      .org-magit-dimmed {
+        /* magit-dimmed */
+        color: #6F6F6F;
+      }
+      .org-magit-filename {
+      }
+      .org-magit-hash {
+        /* magit-hash */
+        color: #6F6F6F;
+      }
+      .org-magit-head {
+        /* magit-head */
+        color: #8CD0D3;
+        font-weight: bold;
+      }
+      .org-magit-header-line {
+        /* magit-header-line */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-magit-header-line-key {
+        /* magit-header-line-key */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-magit-header-line-log-select {
+        /* magit-header-line-log-select */
+        font-weight: bold;
+      }
+      .org-magit-keyword {
+        /* magit-keyword */
+        color: #CC9393;
+      }
+      .org-magit-keyword-squash {
+        /* magit-keyword-squash */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-magit-log-author {
+        /* magit-log-author */
+        color: #DFAF8F;
+      }
+      .org-magit-log-date {
+        /* magit-log-date */
+        color: #656555;
+      }
+      .org-magit-log-graph {
+        /* magit-log-graph */
+        color: #FFFFEF;
+      }
+      .org-magit-mode-line-process {
+        /* magit-mode-line-process */
+        font-weight: bold;
+      }
+      .org-magit-mode-line-process-error {
+        /* magit-mode-line-process-error */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-magit-process-ng {
+        /* magit-process-ng */
+        color: #CC9393;
+        font-weight: bold;
+      }
+      .org-magit-process-ok {
+        /* magit-process-ok */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-magit-reflog-amend {
+        /* magit-reflog-amend */
+        color: #DC8CC3;
+      }
+      .org-magit-reflog-checkout {
+        /* magit-reflog-checkout */
+        color: #8CD0D3;
+      }
+      .org-magit-reflog-cherry-pick {
+        /* magit-reflog-cherry-pick */
+        color: #7F9F7F;
+      }
+      .org-magit-reflog-commit {
+        /* magit-reflog-commit */
+        color: #7F9F7F;
+      }
+      .org-magit-reflog-merge {
+        /* magit-reflog-merge */
+        color: #7F9F7F;
+      }
+      .org-magit-reflog-other {
+        /* magit-reflog-other */
+        color: #93E0E3;
+      }
+      .org-magit-reflog-rebase {
+        /* magit-reflog-rebase */
+        color: #DC8CC3;
+      }
+      .org-magit-reflog-remote {
+        /* magit-reflog-remote */
+        color: #93E0E3;
+      }
+      .org-magit-reflog-reset {
+        /* magit-reflog-reset */
+        color: #CC9393;
+      }
+      .org-magit-refname {
+        /* magit-refname */
+        color: #DCDCCC;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-magit-refname-pullreq {
+        /* magit-refname-pullreq */
+        color: #DCDCCC;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-magit-refname-stash {
+        /* magit-refname-stash */
+        color: #DCDCCC;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-magit-refname-wip {
+        /* magit-refname-wip */
+        color: #DCDCCC;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-magit-section-heading {
+        /* magit-section-heading */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-magit-section-heading-selection {
+        /* magit-section-heading-selection */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-magit-section-highlight {
+        /* magit-section-highlight */
+        background-color: #494949;
+      }
+      .org-magit-section-secondary-heading {
+        /* magit-section-secondary-heading */
+        font-weight: bold;
+      }
+      .org-magit-sequence-done {
+        /* magit-sequence-done */
+        color: #656555;
+      }
+      .org-magit-sequence-drop {
+        /* magit-sequence-drop */
+        color: #CC9393;
+      }
+      .org-magit-sequence-exec {
+        /* magit-sequence-exec */
+        color: #6F6F6F;
+      }
+      .org-magit-sequence-head {
+        /* magit-sequence-head */
+        color: #8CD0D3;
+      }
+      .org-magit-sequence-onto {
+        /* magit-sequence-onto */
+        color: #656555;
+      }
+      .org-magit-sequence-part {
+        /* magit-sequence-part */
+        color: #F0DFAF;
+      }
+      .org-magit-sequence-pick {
+        /* magit-sequence-pick */
+        color: #D0BF8F;
+      }
+      .org-magit-sequence-stop {
+        /* magit-sequence-stop */
+        color: #7F9F7F;
+      }
+      .org-magit-signature-bad {
+        /* magit-signature-bad */
+        color: #CC9393;
+      }
+      .org-magit-signature-error {
+        /* magit-signature-error */
+        color: #CC9393;
+      }
+      .org-magit-signature-expired {
+        /* magit-signature-expired */
+        color: #DFAF8F;
+      }
+      .org-magit-signature-expired-key {
+        /* magit-signature-expired-key */
+        color: #DFAF8F;
+      }
+      .org-magit-signature-good {
+        /* magit-signature-good */
+        color: #7F9F7F;
+      }
+      .org-magit-signature-revoked {
+        /* magit-signature-revoked */
+        color: #DC8CC3;
+      }
+      .org-magit-signature-untrusted {
+        /* magit-signature-untrusted */
+        color: #F0DFAF;
+      }
+      .org-magit-tag {
+        /* magit-tag */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-markdown-blockquote {
+        /* markdown-blockquote-face */
+        color: #9FC59F;
+      }
+      .org-markdown-bold {
+        /* markdown-bold-face */
+        font-weight: bold;
+      }
+      .org-markdown-code {
+      }
+      .org-markdown-comment {
+        /* markdown-comment-face */
+        color: #7F9F7F;
+      }
+      .org-markdown-footnote-marker {
+        /* markdown-footnote-marker-face */
+        color: #b3b3b3;
+      }
+      .org-markdown-footnote-text {
+        /* markdown-footnote-text-face */
+        color: #7F9F7F;
+      }
+      .org-markdown-gfm-checkbox {
+        /* markdown-gfm-checkbox-face */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-markdown-header-delimiter {
+        /* markdown-header-delimiter-face */
+        color: #b3b3b3;
+      }
+      .org-markdown-header-face-1 {
+        /* markdown-header-face-1 */
+        color: #93E0E3;
+        font-weight: bold;
+      }
+      .org-markdown-header-face-2 {
+        /* markdown-header-face-2 */
+        color: #93E0E3;
+        font-weight: bold;
+      }
+      .org-markdown-header-face-3 {
+        /* markdown-header-face-3 */
+        color: #93E0E3;
+        font-weight: bold;
+      }
+      .org-markdown-header-face-4 {
+        /* markdown-header-face-4 */
+        color: #93E0E3;
+        font-weight: bold;
+      }
+      .org-markdown-header-face-5 {
+        /* markdown-header-face-5 */
+        color: #93E0E3;
+        font-weight: bold;
+      }
+      .org-markdown-header-face-6 {
+        /* markdown-header-face-6 */
+        color: #93E0E3;
+        font-weight: bold;
+      }
+      .org-markdown-header-rule {
+        /* markdown-header-rule-face */
+        color: #b3b3b3;
+      }
+      .org-markdown-highlight {
+        /* markdown-highlight-face */
+        background-color: #383838;
+      }
+      .org-markdown-hr {
+        /* markdown-hr-face */
+        color: #b3b3b3;
+      }
+      .org-markdown-html-attr-name {
+        /* markdown-html-attr-name-face */
+        color: #DFAF8F;
+      }
+      .org-markdown-html-attr-value {
+        /* markdown-html-attr-value-face */
+        color: #CC9393;
+      }
+      .org-markdown-html-entity {
+        /* markdown-html-entity-face */
+        color: #DFAF8F;
+      }
+      .org-markdown-html-tag-delimiter {
+        /* markdown-html-tag-delimiter-face */
+        color: #b3b3b3;
+      }
+      .org-markdown-html-tag-name {
+        /* markdown-html-tag-name-face */
+        color: #7CB8BB;
+      }
+      .org-markdown-italic {
+        /* markdown-italic-face */
+        font-style: italic;
+      }
+      .org-markdown-language-info {
+        /* markdown-language-info-face */
+        color: #CC9393;
+      }
+      .org-markdown-language-keyword {
+        /* markdown-language-keyword-face */
+        color: #7CB8BB;
+      }
+      .org-markdown-line-break {
+        /* markdown-line-break-face */
+        color: #BFEBBF;
+        text-decoration: underline;
+      }
+      .org-markdown-link {
+        /* markdown-link-face */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-markdown-link-title {
+        /* markdown-link-title-face */
+        color: #7F9F7F;
+      }
+      .org-markdown-list {
+        /* markdown-list-face */
+        color: #b3b3b3;
+      }
+      .org-markdown-markup {
+        /* markdown-markup-face */
+        color: #b3b3b3;
+      }
+      .org-markdown-math {
+        /* markdown-math-face */
+        color: #CC9393;
+      }
+      .org-markdown-metadata-key {
+        /* markdown-metadata-key-face */
+        color: #DFAF8F;
+      }
+      .org-markdown-metadata-value {
+        /* markdown-metadata-value-face */
+        color: #CC9393;
+      }
+      .org-markdown-missing-link {
+        /* markdown-missing-link-face */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-markdown-plain-url {
+        /* markdown-plain-url-face */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-markdown-reference {
+        /* markdown-reference-face */
+        color: #b3b3b3;
+      }
+      .org-markdown-strike-through {
+        /* markdown-strike-through-face */
+        text-decoration: line-through;
+      }
+      .org-markdown-url {
+        /* markdown-url-face */
+        color: #CC9393;
+      }
+      .org-match {
+        /* match */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-mcXcursor {
+      }
+      .org-mcXcursor-bar {
+        /* mc/cursor-bar-face */
+        background-color: #000000;
+      }
+      .org-mcXregion {
+        /* mc/region-face */
+        background-color: #2B2B2B;
+      }
+      .org-menu {
+        /* menu */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-message-cited-text-1 {
+        /* message-cited-text-1 */
+        color: #7F9F7F;
+      }
+      .org-message-cited-text-2 {
+        /* message-cited-text-2 */
+        color: #228b22;
+      }
+      .org-message-cited-text-3 {
+        /* message-cited-text-3 */
+        color: #cd9b1d;
+      }
+      .org-message-cited-text-4 {
+        /* message-cited-text-4 */
+        color: #cd661d;
+      }
+      .org-message-header-cc {
+        /* message-header-cc */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-message-header-name {
+        /* message-header-name */
+        color: #8FB28F;
+      }
+      .org-message-header-newsgroups {
+        /* message-header-newsgroups */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-message-header-other {
+        /* message-header-other */
+        color: #7F9F7F;
+      }
+      .org-message-header-subject {
+        /* message-header-subject */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-message-header-to {
+        /* message-header-to */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-message-header-xheader {
+        /* message-header-xheader */
+        color: #7F9F7F;
+      }
+      .org-message-mml {
+        /* message-mml */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-message-separator {
+        /* message-separator */
+        color: #7F9F7F;
+      }
+      .org-minibuffer-prompt {
+        /* minibuffer-prompt */
+        color: #F0DFAF;
+      }
+      .org-mm-command-output {
+        /* mm-command-output */
+        color: #228b22;
+      }
+      .org-mm-uu-extract {
+        /* mm-uu-extract */
+        color: #8FB28F;
+        background-color: #383838;
+      }
+      .org-mode-line {
+        /* mode-line */
+        color: #8FB28F;
+        background-color: #2B2B2B;
+      }
+      .org-mode-line-buffer-id {
+        /* mode-line-buffer-id */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-mode-line-emphasis {
+        /* mode-line-emphasis */
+        font-weight: bold;
+      }
+      .org-mode-line-highlight {
+      }
+      .org-mode-line-inactive {
+        /* mode-line-inactive */
+        color: #5F7F5F;
+        background-color: #383838;
+      }
+      .org-mouse {
+      }
+      .org-mouse-drag-and-drop-region {
+        /* mouse-drag-and-drop-region */
+        background-color: #2B2B2B;
+      }
+      .org-negation-char {
+        /* font-lock-negation-char-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-neo-banner {
+        /* neo-banner-face */
+        color: #94BFF3;
+        font-weight: bold;
+      }
+      .org-neo-button {
+      }
+      .org-neo-dir-link {
+        /* neo-dir-link-face */
+        color: #8CD0D3;
+      }
+      .org-neo-expand-btn {
+        /* neo-expand-btn-face */
+        color: #8CD0D3;
+      }
+      .org-neo-file-link {
+        /* neo-file-link-face */
+        color: #DCDCCC;
+      }
+      .org-neo-header {
+        /* neo-header-face */
+        color: #DCDCCC;
+      }
+      .org-neo-root-dir {
+        /* neo-root-dir-face */
+        color: #94BFF3;
+        font-weight: bold;
+      }
+      .org-neo-vc-added {
+        /* neo-vc-added-face */
+        color: #8FB28F;
+      }
+      .org-neo-vc-conflict {
+        /* neo-vc-conflict-face */
+        color: #DCA3A3;
+      }
+      .org-neo-vc-default {
+        /* neo-vc-default-face */
+        color: #FFFFEF;
+      }
+      .org-neo-vc-edited {
+        /* neo-vc-edited-face */
+        color: #DC8CC3;
+      }
+      .org-neo-vc-ignored {
+        /* neo-vc-ignored-face */
+        color: #656555;
+      }
+      .org-neo-vc-missing {
+        /* neo-vc-missing-face */
+        color: #DCA3A3;
+      }
+      .org-neo-vc-needs-merge {
+        /* neo-vc-needs-merge-face */
+        color: #DCA3A3;
+      }
+      .org-neo-vc-needs-update {
+        /* neo-vc-needs-update-face */
+        text-decoration: underline;
+      }
+      .org-neo-vc-removed {
+        /* neo-vc-removed-face */
+        text-decoration: line-through;
+      }
+      .org-neo-vc-unlocked-changes {
+        /* neo-vc-unlocked-changes-face */
+        color: #CC9393;
+        background-color: #366060;
+      }
+      .org-neo-vc-unregistered {
+      }
+      .org-neo-vc-up-to-date {
+        /* neo-vc-up-to-date-face */
+        color: #DCDCCC;
+      }
+      .org-neo-vc-user {
+        /* neo-vc-user-face */
+        color: #CC9393;
+        font-style: italic;
+      }
+      .org-next-error {
+        /* next-error */
+        background-color: #2B2B2B;
+      }
+      .org-next-error-message {
+        /* next-error-message */
+        background-color: #383838;
+      }
+      .org-nim-font-lock-export {
+        /* nim-font-lock-export-face */
+        color: #93E0E3;
+        font-weight: bold;
+        font-style: italic;
+      }
+      .org-nim-font-lock-number {
+        /* nim-font-lock-number-face */
+        font-style: italic;
+      }
+      .org-nim-font-lock-pragma {
+        /* nim-font-lock-pragma-face */
+        color: #94BFF3;
+      }
+      .org-nim-non-overloadable {
+        /* nim-non-overloadable-face */
+        color: #DCDCCC;
+        font-weight: bold;
+        font-style: italic;
+      }
+      .org-nix-antiquote {
+        /* nix-antiquote-face */
+        color: #94BFF3;
+      }
+      .org-nix-attribute {
+        /* nix-attribute-face */
+        color: #DFAF8F;
+      }
+      .org-nix-builtin {
+        /* nix-builtin-face */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-nix-constant {
+        /* nix-constant-face */
+        color: #BFEBBF;
+      }
+      .org-nix-keyword {
+        /* nix-keyword-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-nix-keyword-warning {
+        /* nix-keyword-warning-face */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-nobreak-hyphen {
+        /* nobreak-hyphen */
+        color: #00ffff;
+      }
+      .org-nobreak-space {
+        /* nobreak-space */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-org-agenda-calendar-event {
+        /* org-agenda-calendar-event */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-org-agenda-calendar-sexp {
+        /* org-agenda-calendar-sexp */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-org-agenda-clocking {
+        /* org-agenda-clocking */
+        background-color: #5F5F5F;
+      }
+      .org-org-agenda-column-dateline {
+        /* org-agenda-column-dateline */
+        background-color: #2B2B2B;
+      }
+      .org-org-agenda-current-time {
+        /* org-agenda-current-time */
+        color: #DFAF8F;
+      }
+      .org-org-agenda-date {
+        /* org-agenda-date */
+        color: #7F9F7F;
+      }
+      .org-org-agenda-date-today {
+        /* org-agenda-date-today */
+        color: #FFFFEF;
+        font-weight: bold;
+        font-style: italic;
+      }
+      .org-org-agenda-date-weekend {
+        /* org-agenda-date-weekend */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-org-agenda-diary {
+        /* org-agenda-diary */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-org-agenda-dimmed-todo {
+        /* org-agenda-dimmed-todo-face */
+        color: #7f7f7f;
+      }
+      .org-org-agenda-done {
+        /* org-agenda-done */
+        color: #98fb98;
+      }
+      .org-org-agenda-filter-category {
+        /* org-agenda-filter-category */
+        color: #8FB28F;
+        background-color: #2B2B2B;
+      }
+      .org-org-agenda-filter-effort {
+        /* org-agenda-filter-effort */
+        color: #8FB28F;
+        background-color: #2B2B2B;
+      }
+      .org-org-agenda-filter-regexp {
+        /* org-agenda-filter-regexp */
+        color: #8FB28F;
+        background-color: #2B2B2B;
+      }
+      .org-org-agenda-filter-tags {
+        /* org-agenda-filter-tags */
+        color: #8FB28F;
+        background-color: #2B2B2B;
+      }
+      .org-org-agenda-restriction-lock {
+        /* org-agenda-restriction-lock */
+        background-color: #1C1C1C;
+      }
+      .org-org-agenda-structure {
+        /* org-agenda-structure */
+        color: #7F9F7F;
+      }
+      .org-org-archived {
+        /* org-archived */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-org-beamer-tag {
+      }
+      .org-org-block {
+        /* org-block */
+        background-color: #494949;
+      }
+      .org-org-block-begin-line {
+        /* org-block-begin-line */
+        color: #7F9F7F;
+      }
+      .org-org-block-end-line {
+        /* org-block-end-line */
+        color: #7F9F7F;
+      }
+      .org-org-checkbox {
+        /* org-checkbox */
+        color: #FFFFEF;
+        background-color: #5F5F5F;
+      }
+      .org-org-checkbox-statistics-done {
+        /* org-checkbox-statistics-done */
+        color: #AFD8AF;
+        font-weight: bold;
+      }
+      .org-org-checkbox-statistics-todo {
+        /* org-checkbox-statistics-todo */
+        color: #CC9393;
+        font-weight: bold;
+      }
+      .org-org-clock-overlay {
+        /* org-clock-overlay */
+        color: #ffffff;
+        background-color: #4a708b;
+      }
+      .org-org-code {
+        /* org-code */
+        color: #b3b3b3;
+      }
+      .org-org-column {
+        /* org-column */
+        background-color: #2B2B2B;
+      }
+      .org-org-column-title {
+        /* org-column-title */
+        background-color: #2B2B2B;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-org-date {
+        /* org-date */
+        color: #8CD0D3;
+        text-decoration: underline;
+      }
+      .org-org-date-selected {
+        /* org-date-selected */
+        color: #ffc0cb;
+      }
+      .org-org-default {
+        /* org-default */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-org-document-info {
+        /* org-document-info */
+        color: #8CD0D3;
+      }
+      .org-org-document-info-keyword {
+        /* org-document-info-keyword */
+        color: #b3b3b3;
+      }
+      .org-org-document-title {
+        /* org-document-title */
+        color: #8CD0D3;
+        background-color: #3F3F3F;
+        font-weight: bold;
+      }
+      .org-org-done {
+        /* org-done */
+        color: #AFD8AF;
+        font-weight: bold;
+      }
+      .org-org-drawer {
+        /* org-drawer */
+        color: #87cefa;
+      }
+      .org-org-ellipsis {
+        /* org-ellipsis */
+        color: #E0CF9F;
+        text-decoration: underline;
+      }
+      .org-org-footnote {
+        /* org-footnote */
+        color: #93E0E3;
+        text-decoration: underline;
+      }
+      .org-org-formula {
+        /* org-formula */
+        color: #D0BF8F;
+      }
+      .org-org-habit-alert {
+        /* org-habit-alert-face */
+        color: #3F3F3F;
+        background-color: #E0CF9F;
+      }
+      .org-org-habit-alert-future {
+        /* org-habit-alert-future-face */
+        color: #3F3F3F;
+        background-color: #D0BF8F;
+      }
+      .org-org-habit-clear {
+        /* org-habit-clear-face */
+        background-color: #5C888B;
+      }
+      .org-org-habit-clear-future {
+        /* org-habit-clear-future-face */
+        background-color: #4C7073;
+      }
+      .org-org-habit-overdue {
+        /* org-habit-overdue-face */
+        background-color: #9C6363;
+      }
+      .org-org-habit-overdue-future {
+        /* org-habit-overdue-future-face */
+        background-color: #8C5353;
+      }
+      .org-org-habit-ready {
+        /* org-habit-ready-face */
+        background-color: #7F9F7F;
+      }
+      .org-org-habit-ready-future {
+        /* org-habit-ready-future-face */
+        background-color: #5F7F5F;
+      }
+      .org-org-headline-done {
+        /* org-headline-done */
+        color: #AFD8AF;
+      }
+      .org-org-headline-todo {
+        /* org-headline-todo */
+        color: #eea9b8;
+      }
+      .org-org-hide {
+        /* org-hide */
+        color: #3F3F3F;
+      }
+      .org-org-indent {
+        /* org-indent */
+        color: #3F3F3F;
+      }
+      .org-org-journal-calendar-entry {
+        /* org-journal-calendar-entry-face */
+        color: #aa0000;
+        font-style: italic;
+      }
+      .org-org-journal-calendar-scheduled {
+        /* org-journal-calendar-scheduled-face */
+        color: #600000;
+        font-style: italic;
+      }
+      .org-org-journal-highlight {
+        /* org-journal-highlight */
+        color: #ff1493;
+      }
+      .org-org-latex-and-related {
+        /* org-latex-and-related */
+        color: #deb887;
+      }
+      .org-org-level-1 {
+        /* org-level-1 */
+        color: #DFAF8F;
+        background-color: #3F3F3F;
+      }
+      .org-org-level-2 {
+        /* org-level-2 */
+        color: #BFEBBF;
+        background-color: #3F3F3F;
+      }
+      .org-org-level-3 {
+        /* org-level-3 */
+        color: #7CB8BB;
+        background-color: #3F3F3F;
+      }
+      .org-org-level-4 {
+        /* org-level-4 */
+        color: #D0BF8F;
+        background-color: #3F3F3F;
+      }
+      .org-org-level-5 {
+        /* org-level-5 */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+      }
+      .org-org-level-6 {
+        /* org-level-6 */
+        color: #9FC59F;
+        background-color: #3F3F3F;
+      }
+      .org-org-level-7 {
+        /* org-level-7 */
+        color: #8C5353;
+        background-color: #3F3F3F;
+      }
+      .org-org-level-8 {
+        /* org-level-8 */
+        color: #4C7073;
+        background-color: #3F3F3F;
+      }
+      .org-org-link {
+        /* org-link */
+        color: #D0BF8F;
+        text-decoration: underline;
+      }
+      .org-org-list-dt {
+        /* org-list-dt */
+        font-weight: bold;
+      }
+      .org-org-macro {
+        /* org-macro */
+        color: #deb887;
+      }
+      .org-org-meta-line {
+        /* org-meta-line */
+        color: #7F9F7F;
+      }
+      .org-org-mode-line-clock {
+        /* org-mode-line-clock */
+        color: #DCDCCC;
+        background-color: #2B2B2B;
+      }
+      .org-org-mode-line-clock-overrun {
+        /* org-mode-line-clock-overrun */
+        color: #3F3F3F;
+        background-color: #BC8383;
+      }
+      .org-org-pomodoro-mode-line {
+        /* org-pomodoro-mode-line */
+        color: #ff6347;
+      }
+      .org-org-pomodoro-mode-line-break {
+        /* org-pomodoro-mode-line-break */
+        color: #2aa198;
+      }
+      .org-org-pomodoro-mode-line-overtime {
+        /* org-pomodoro-mode-line-overtime */
+        color: #cd4f39;
+        font-weight: bold;
+      }
+      .org-org-priority {
+        /* org-priority */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-org-property-value {
+      }
+      .org-org-quote {
+        /* org-quote */
+        background-color: #494949;
+      }
+      .org-org-scheduled {
+        /* org-scheduled */
+        color: #BFEBBF;
+      }
+      .org-org-scheduled-previously {
+        /* org-scheduled-previously */
+        color: #CC9393;
+      }
+      .org-org-scheduled-today {
+        /* org-scheduled-today */
+        color: #94BFF3;
+      }
+      .org-org-sexp-date {
+        /* org-sexp-date */
+        color: #94BFF3;
+        text-decoration: underline;
+      }
+      .org-org-special-keyword {
+        /* org-special-keyword */
+        color: #7F9F7F;
+      }
+      .org-org-super-agenda-header {
+        /* org-super-agenda-header */
+        color: #7F9F7F;
+      }
+      .org-org-table {
+        /* org-table */
+        color: #9FC59F;
+      }
+      .org-org-table-header {
+        /* org-table-header */
+        color: #000000;
+        background-color: #d3d3d3;
+      }
+      .org-org-tag {
+        /* org-tag */
+        font-weight: bold;
+      }
+      .org-org-tag-group {
+        /* org-tag-group */
+        font-weight: bold;
+      }
+      .org-org-target {
+        /* org-target */
+        text-decoration: underline;
+      }
+      .org-org-time-grid {
+        /* org-time-grid */
+        color: #DFAF8F;
+      }
+      .org-org-todo {
+        /* org-todo */
+        color: #CC9393;
+        font-weight: bold;
+      }
+      .org-org-upcoming-deadline {
+        /* org-upcoming-deadline */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-org-upcoming-distant-deadline {
+        /* org-upcoming-distant-deadline */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-org-verbatim {
+        /* org-verbatim */
+        color: #b3b3b3;
+      }
+      .org-org-verse {
+        /* org-verse */
+        background-color: #494949;
+      }
+      .org-org-warning {
+        /* org-warning */
+        color: #CC9393;
+        font-weight: bold;
+      }
+      .org-outline-1 {
+        /* outline-1 */
+        color: #DFAF8F;
+        background-color: #3F3F3F;
+      }
+      .org-outline-2 {
+        /* outline-2 */
+        color: #BFEBBF;
+        background-color: #3F3F3F;
+      }
+      .org-outline-3 {
+        /* outline-3 */
+        color: #7CB8BB;
+        background-color: #3F3F3F;
+      }
+      .org-outline-4 {
+        /* outline-4 */
+        color: #D0BF8F;
+        background-color: #3F3F3F;
+      }
+      .org-outline-5 {
+        /* outline-5 */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+      }
+      .org-outline-6 {
+        /* outline-6 */
+        color: #9FC59F;
+        background-color: #3F3F3F;
+      }
+      .org-outline-7 {
+        /* outline-7 */
+        color: #8C5353;
+        background-color: #3F3F3F;
+      }
+      .org-outline-8 {
+        /* outline-8 */
+        color: #4C7073;
+        background-color: #3F3F3F;
+      }
+      .org-outshine-level-1 {
+        /* outshine-level-1 */
+        color: #DFAF8F;
+        background-color: #3F3F3F;
+      }
+      .org-outshine-level-2 {
+        /* outshine-level-2 */
+        color: #BFEBBF;
+        background-color: #3F3F3F;
+      }
+      .org-outshine-level-3 {
+        /* outshine-level-3 */
+        color: #7CB8BB;
+        background-color: #3F3F3F;
+      }
+      .org-outshine-level-4 {
+        /* outshine-level-4 */
+        color: #D0BF8F;
+        background-color: #3F3F3F;
+      }
+      .org-outshine-level-5 {
+        /* outshine-level-5 */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+      }
+      .org-outshine-level-6 {
+        /* outshine-level-6 */
+        color: #9FC59F;
+        background-color: #3F3F3F;
+      }
+      .org-outshine-level-7 {
+        /* outshine-level-7 */
+        color: #8C5353;
+        background-color: #3F3F3F;
+      }
+      .org-outshine-level-8 {
+        /* outshine-level-8 */
+        color: #4C7073;
+        background-color: #3F3F3F;
+      }
+      .org-package-description {
+        /* package-description */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-package-name {
+        /* package-name */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-package-status-avail-obso {
+        /* package-status-avail-obso */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-package-status-available {
+        /* package-status-available */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-package-status-built-in {
+        /* package-status-built-in */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-package-status-dependency {
+        /* package-status-dependency */
+        color: #7F9F7F;
+      }
+      .org-package-status-disabled {
+        /* package-status-disabled */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-package-status-external {
+        /* package-status-external */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-package-status-held {
+        /* package-status-held */
+        color: #BFEBBF;
+      }
+      .org-package-status-incompat {
+        /* package-status-incompat */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-package-status-installed {
+        /* package-status-installed */
+        color: #7F9F7F;
+      }
+      .org-package-status-unsigned {
+        /* package-status-unsigned */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-popup {
+        /* popup-face */
+        color: #000000;
+        background-color: #d3d3d3;
+      }
+      .org-popup-isearch-match {
+        /* popup-isearch-match */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-popup-menu {
+        /* popup-menu-face */
+        color: #000000;
+        background-color: #d3d3d3;
+      }
+      .org-popup-menu-mouse {
+        /* popup-menu-mouse-face */
+        color: #000000;
+        background-color: #D0BF8F;
+      }
+      .org-popup-menu-selection {
+        /* popup-menu-selection-face */
+        color: #ffffff;
+        background-color: #4682b4;
+      }
+      .org-popup-menu-summary {
+        /* popup-menu-summary-face */
+        color: #000000;
+        background-color: #6F6F6F;
+      }
+      .org-popup-scroll-bar-background {
+        /* popup-scroll-bar-background-face */
+        background-color: #2B2B2B;
+      }
+      .org-popup-scroll-bar-foreground {
+        /* popup-scroll-bar-foreground-face */
+        background-color: #366060;
+      }
+      .org-popup-summary {
+        /* popup-summary-face */
+        color: #000000;
+        background-color: #6F6F6F;
+      }
+      .org-popup-tip {
+        /* popup-tip-face */
+        color: #000000;
+        background-color: #D0BF8F;
+      }
+      .org-preprocessor {
+        /* font-lock-preprocessor-face */
+        color: #94BFF3;
+      }
+      .org-prodigy-green {
+        /* prodigy-green-face */
+        color: #61b361;
+      }
+      .org-prodigy-red {
+        /* prodigy-red-face */
+        color: #cd4d40;
+      }
+      .org-prodigy-yellow {
+        /* prodigy-yellow-face */
+        color: #e7e24c;
+      }
+      .org-pulse-highlight {
+        /* pulse-highlight-face */
+        background-color: #AAAA33;
+      }
+      .org-pulse-highlight-start {
+        /* pulse-highlight-start-face */
+        background-color: #AAAA33;
+      }
+      .org-query-replace {
+        /* query-replace */
+        color: #D0BF8F;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-racket-debug-break {
+        /* racket-debug-break-face */
+        background-color: #ff0000;
+      }
+      .org-racket-debug-locals {
+        /* racket-debug-locals-face */
+        color: #7CB8BB;
+        font-style: italic;
+      }
+      .org-racket-debug-result {
+        /* racket-debug-result-face */
+        color: #7CB8BB;
+        font-weight: bold;
+        font-style: italic;
+      }
+      .org-racket-here-string {
+        /* racket-here-string-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-racket-keyword-argument {
+        /* racket-keyword-argument-face */
+        color: #BFEBBF;
+      }
+      .org-racket-logger-config {
+        /* racket-logger-config-face */
+        color: #7F9F7F;
+        font-style: italic;
+      }
+      .org-racket-logger-debug {
+        /* racket-logger-debug-face */
+        color: #BFEBBF;
+      }
+      .org-racket-logger-error {
+        /* racket-logger-error-face */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-racket-logger-fatal {
+        /* racket-logger-fatal-face */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-racket-logger-info {
+        /* racket-logger-info-face */
+        color: #CC9393;
+      }
+      .org-racket-logger-topic {
+        /* racket-logger-topic-face */
+        color: #93E0E3;
+        font-style: italic;
+      }
+      .org-racket-logger-warning {
+        /* racket-logger-warning-face */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-racket-selfeval {
+        /* racket-selfeval-face */
+        color: #7CB8BB;
+      }
+      .org-racket-xp-def {
+        /* racket-xp-def-face */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-racket-xp-error {
+        /* racket-xp-error-face */
+        text-decoration: underline;
+      }
+      .org-racket-xp-tail-position {
+        /* racket-xp-tail-position-face */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-racket-xp-tail-target {
+        /* racket-xp-tail-target-face */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-racket-xp-unused {
+        /* racket-xp-unused-face */
+        text-decoration: line-through;
+      }
+      .org-racket-xp-use {
+        /* racket-xp-use-face */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-read-multiple-choice {
+        /* read-multiple-choice-face */
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-reb-match-0 {
+        /* reb-match-0 */
+        color: #3F3F3F;
+        background-color: #DC8CC3;
+      }
+      .org-reb-match-1 {
+        /* reb-match-1 */
+        color: #3F3F3F;
+        background-color: #8CD0D3;
+      }
+      .org-reb-match-2 {
+        /* reb-match-2 */
+        color: #3F3F3F;
+        background-color: #DFAF8F;
+      }
+      .org-reb-match-3 {
+        /* reb-match-3 */
+        color: #3F3F3F;
+        background-color: #CC9393;
+      }
+      .org-reb-regexp-grouping-backslash {
+        /* reb-regexp-grouping-backslash */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-reb-regexp-grouping-construct {
+        /* reb-regexp-grouping-construct */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-rectangle-preview {
+        /* rectangle-preview */
+        background-color: #2B2B2B;
+      }
+      .org-regexp-grouping-backslash {
+        /* font-lock-regexp-grouping-backslash */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-regexp-grouping-construct {
+        /* font-lock-regexp-grouping-construct */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-region {
+        /* region */
+        background-color: #2B2B2B;
+      }
+      .org-rg-column-number {
+        /* rg-column-number-face */
+        color: #9FC59F;
+      }
+      .org-rg-context {
+        /* rg-context-face */
+        color: #b3b3b3;
+      }
+      .org-rg-error {
+        /* rg-error-face */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-rg-file-tag {
+        /* rg-file-tag-face */
+        color: #BFEBBF;
+        text-decoration: underline;
+      }
+      .org-rg-filename {
+        /* rg-filename-face */
+        color: #BFEBBF;
+        text-decoration: underline;
+      }
+      .org-rg-info {
+        /* rg-info-face */
+        color: #BFEBBF;
+        text-decoration: underline;
+      }
+      .org-rg-line-number {
+        /* rg-line-number-face */
+        color: #F0DFAF;
+      }
+      .org-rg-literal {
+        /* rg-literal-face */
+        color: #BFEBBF;
+        text-decoration: underline;
+      }
+      .org-rg-match {
+        /* rg-match-face */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-rg-match-position {
+        /* rg-match-position-face */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-rg-regexp {
+        /* rg-regexp-face */
+        color: #F0DFAF;
+      }
+      .org-rg-toggle-off {
+        /* rg-toggle-off-face */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-rg-toggle-on {
+        /* rg-toggle-on-face */
+        color: #BFEBBF;
+        text-decoration: underline;
+      }
+      .org-rg-warning {
+        /* rg-warning-face */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-rmail-header-name {
+        /* rmail-header-name */
+        color: #93E0E3;
+      }
+      .org-rmail-highlight {
+        /* rmail-highlight */
+        background-color: #383838;
+      }
+      .org-rxt-highlight {
+        /* rxt-highlight-face */
+        background-color: #222222;
+      }
+      .org-scroll-bar {
+        /* scroll-bar */
+        color: #ffffff;
+      }
+      .org-secondary-selection {
+        /* secondary-selection */
+        background-color: #5F5F5F;
+      }
+      .org-semantic-highlight-edits {
+        /* semantic-highlight-edits-face */
+        background-color: #333333;
+      }
+      .org-semantic-highlight-func-current-tag {
+        /* semantic-highlight-func-current-tag-face */
+        background-color: #333333;
+      }
+      .org-semantic-unmatched-syntax {
+        /* semantic-unmatched-syntax-face */
+        text-decoration: underline;
+      }
+      .org-sesman-browser-button {
+        /* sesman-browser-button-face */
+        font-style: italic;
+        text-decoration: underline;
+      }
+      .org-sesman-browser-highligh {
+        /* sesman-browser-highligh-face */
+        background-color: #383838;
+        font-weight: bold;
+      }
+      .org-sesman-buffer {
+        /* sesman-buffer-face */
+        color: #94BFF3;
+      }
+      .org-sesman-directory {
+        /* sesman-directory-face */
+        color: #7CB8BB;
+      }
+      .org-sesman-project {
+        /* sesman-project-face */
+        color: #9FC59F;
+      }
+      .org-sgml-namespace {
+        /* sgml-namespace */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-sh-escaped-newline {
+        /* sh-escaped-newline */
+        color: #CC9393;
+      }
+      .org-sh-heredoc {
+        /* sh-heredoc */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-sh-quoted-exec {
+        /* sh-quoted-exec */
+        color: #CC9393;
+      }
+      .org-shadow {
+        /* shadow */
+        color: #b3b3b3;
+      }
+      .org-shortdoc-heading {
+        /* shortdoc-heading */
+        font-size: 130%;
+        font-weight: bold;
+      }
+      .org-shortdoc-section {
+      }
+      .org-shortdoc-separator {
+        /* shortdoc-separator */
+        background-color: #505050;
+        font-size: 10%;
+      }
+      .org-show-paren-match {
+        /* show-paren-match */
+        color: #DCDCCC;
+        background-color: #6F6F6F;
+        font-weight: bold;
+      }
+      .org-show-paren-match-expression {
+        /* show-paren-match-expression */
+        color: #DCDCCC;
+        background-color: #6F6F6F;
+        font-weight: bold;
+      }
+      .org-show-paren-mismatch {
+        /* show-paren-mismatch */
+        color: #DCA3A3;
+        background-color: #6F6F6F;
+        font-weight: bold;
+      }
+      .org-show-tabs-space {
+        /* show-tabs-space */
+        background-color: #ffff00;
+      }
+      .org-show-tabs-tab {
+        /* show-tabs-tab */
+        background-color: #ff0000;
+      }
+      .org-shr-abbreviation {
+        /* shr-abbreviation */
+        text-decoration: underline;
+      }
+      .org-shr-link {
+        /* shr-link */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-shr-selected-link {
+        /* shr-selected-link */
+        color: #F0DFAF;
+        background-color: #ff0000;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-shr-strike-through {
+        /* shr-strike-through */
+        text-decoration: line-through;
+      }
+      .org-shrface-code {
+        /* shrface-code */
+        color: #b3b3b3;
+      }
+      .org-shrface-description-list-term {
+        /* shrface-description-list-term-face */
+        font-weight: bold;
+      }
+      .org-shrface-figure {
+        /* shrface-figure */
+        color: #9FC59F;
+      }
+      .org-shrface-h1 {
+        /* shrface-h1-face */
+        color: #DFAF8F;
+        background-color: #3F3F3F;
+      }
+      .org-shrface-h2 {
+        /* shrface-h2-face */
+        color: #BFEBBF;
+        background-color: #3F3F3F;
+      }
+      .org-shrface-h3 {
+        /* shrface-h3-face */
+        color: #7CB8BB;
+        background-color: #3F3F3F;
+      }
+      .org-shrface-h4 {
+        /* shrface-h4-face */
+        color: #D0BF8F;
+        background-color: #3F3F3F;
+      }
+      .org-shrface-h5 {
+        /* shrface-h5-face */
+        color: #93E0E3;
+        background-color: #3F3F3F;
+      }
+      .org-shrface-h6 {
+        /* shrface-h6-face */
+        color: #9FC59F;
+        background-color: #3F3F3F;
+      }
+      .org-shrface-highlight {
+      }
+      .org-shrface-href {
+        /* shrface-href-face */
+        color: #D0BF8F;
+        text-decoration: underline;
+      }
+      .org-shrface-href-file {
+        /* shrface-href-file-face */
+        color: #87cefa;
+        text-decoration: underline;
+      }
+      .org-shrface-href-ftp {
+        /* shrface-href-ftp-face */
+        color: #5E81AC;
+        text-decoration: underline;
+      }
+      .org-shrface-href-http {
+        /* shrface-href-http-face */
+        color: #39CCCC;
+        text-decoration: underline;
+      }
+      .org-shrface-href-https {
+        /* shrface-href-https-face */
+        color: #7FDBFF;
+        text-decoration: underline;
+      }
+      .org-shrface-href-mailto {
+        /* shrface-href-mailto-face */
+        color: #8FBCBB;
+        text-decoration: underline;
+      }
+      .org-shrface-href-other {
+        /* shrface-href-other-face */
+        color: #81A1C1;
+        text-decoration: underline;
+      }
+      .org-shrface-item-bullet {
+        /* shrface-item-bullet-face */
+        font-weight: bold;
+      }
+      .org-shrface-item-number {
+        /* shrface-item-number-face */
+        font-weight: bold;
+      }
+      .org-shrface-links-mouse {
+      }
+      .org-shrface-links-title {
+        /* shrface-links-title-face */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-shrface-links-url {
+        /* shrface-links-url-face */
+        color: #7F9F7F;
+      }
+      .org-shrface-verbatim {
+        /* shrface-verbatim */
+        color: #b3b3b3;
+      }
+      .org-sly-action {
+        /* sly-action-face */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-sly-apropos-label {
+        /* sly-apropos-label */
+        font-style: italic;
+      }
+      .org-sly-apropos-symbol {
+        /* sly-apropos-symbol */
+        color: #BFEBBF;
+      }
+      .org-sly-db-catch-tag {
+      }
+      .org-sly-db-condition {
+        /* sly-db-condition-face */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-sly-db-frame-label {
+        /* sly-db-frame-label-face */
+        color: #b3b3b3;
+      }
+      .org-sly-db-frame-line {
+      }
+      .org-sly-db-local-name {
+      }
+      .org-sly-db-non-restartable-frame-line {
+      }
+      .org-sly-db-restart {
+      }
+      .org-sly-db-restart-number {
+        /* sly-db-restart-number-face */
+        color: #b3b3b3;
+      }
+      .org-sly-db-restartable-frame-line {
+        /* sly-db-restartable-frame-line-face */
+        color: #BFEBBF;
+      }
+      .org-sly-db-section {
+        /* sly-db-section-face */
+        color: #F0DFAF;
+        background-color: #2B2B2B;
+      }
+      .org-sly-db-topline {
+      }
+      .org-sly-error {
+        /* sly-error-face */
+        text-decoration: underline;
+      }
+      .org-sly-mode-line {
+        /* sly-mode-line */
+        color: #BFEBBF;
+        font-weight: bold;
+      }
+      .org-sly-note {
+        /* sly-note-face */
+        text-decoration: underline;
+      }
+      .org-sly-part-button {
+        /* sly-part-button-face */
+        color: #BFEBBF;
+      }
+      .org-sly-style-warning {
+        /* sly-style-warning-face */
+        text-decoration: underline;
+      }
+      .org-sly-warning {
+        /* sly-warning-face */
+        text-decoration: underline;
+      }
+      .org-smerge-base {
+        /* smerge-base */
+        background-color: #888833;
+      }
+      .org-smerge-lower {
+        /* smerge-lower */
+        background-color: #335533;
+      }
+      .org-smerge-markers {
+        /* smerge-markers */
+        background-color: #4d4d4d;
+      }
+      .org-smerge-refined-added {
+        /* smerge-refined-added */
+        background-color: #22aa22;
+      }
+      .org-smerge-refined-changed {
+      }
+      .org-smerge-refined-removed {
+        /* smerge-refined-removed */
+        background-color: #aa2222;
+      }
+      .org-smerge-upper {
+        /* smerge-upper */
+        background-color: #553333;
+      }
+      .org-so-long-mode-line-active {
+        /* so-long-mode-line-active */
+        font-weight: bold;
+      }
+      .org-so-long-mode-line-inactive {
+        /* so-long-mode-line-inactive */
+        color: #5F7F5F;
+        background-color: #383838;
+      }
+      .org-sp-pair-overlay {
+        /* sp-pair-overlay-face */
+        background-color: #383838;
+      }
+      .org-sp-show-pair-enclosing {
+        /* sp-show-pair-enclosing */
+        background-color: #383838;
+      }
+      .org-sp-show-pair-match {
+        /* sp-show-pair-match-face */
+        background-color: #6F6F6F;
+        font-weight: bold;
+      }
+      .org-sp-show-pair-match-content {
+      }
+      .org-sp-show-pair-mismatch {
+        /* sp-show-pair-mismatch-face */
+        color: #DCA3A3;
+        background-color: #6F6F6F;
+        font-weight: bold;
+      }
+      .org-sp-wrap-overlay {
+        /* sp-wrap-overlay-face */
+        background-color: #383838;
+      }
+      .org-sp-wrap-overlay-closing-pair {
+        /* sp-wrap-overlay-closing-pair */
+        color: #ff0000;
+        background-color: #383838;
+      }
+      .org-sp-wrap-overlay-opening-pair {
+        /* sp-wrap-overlay-opening-pair */
+        color: #00ff00;
+        background-color: #383838;
+      }
+      .org-sp-wrap-tag-overlay {
+        /* sp-wrap-tag-overlay-face */
+        background-color: #383838;
+      }
+      .org-speedbar-button {
+        /* speedbar-button-face */
+        color: #9FC59F;
+      }
+      .org-speedbar-directory {
+        /* speedbar-directory-face */
+        color: #93E0E3;
+      }
+      .org-speedbar-file {
+        /* speedbar-file-face */
+        color: #DCDCCC;
+      }
+      .org-speedbar-highlight {
+        /* speedbar-highlight-face */
+        color: #3F3F3F;
+        background-color: #9FC59F;
+      }
+      .org-speedbar-selected {
+        /* speedbar-selected-face */
+        color: #CC9393;
+      }
+      .org-speedbar-separator {
+        /* speedbar-separator-face */
+        color: #3F3F3F;
+        background-color: #7CB8BB;
+      }
+      .org-speedbar-tag {
+        /* speedbar-tag-face */
+        color: #F0DFAF;
+      }
+      .org-string {
+        /* font-lock-string-face */
+        color: #CC9393;
+      }
+      .org-success {
+        /* success */
+        color: #7F9F7F;
+        font-weight: bold;
+      }
+      .org-swiper-background-match-face-1 {
+        /* swiper-background-match-face-1 */
+        color: #D0BF8F;
+        background-color: #383838;
+        font-weight: bold;
+      }
+      .org-swiper-background-match-face-2 {
+        /* swiper-background-match-face-2 */
+        color: #D0BF8F;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-swiper-background-match-face-3 {
+        /* swiper-background-match-face-3 */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-swiper-background-match-face-4 {
+        /* swiper-background-match-face-4 */
+        color: #DCDCCC;
+        background-color: #8C5353;
+      }
+      .org-swiper-line {
+        /* swiper-line-face */
+        text-decoration: underline;
+      }
+      .org-swiper-match-face-1 {
+        /* swiper-match-face-1 */
+        color: #D0BF8F;
+        background-color: #383838;
+        font-weight: bold;
+      }
+      .org-swiper-match-face-2 {
+        /* swiper-match-face-2 */
+        color: #D0BF8F;
+        background-color: #5F5F5F;
+        font-weight: bold;
+      }
+      .org-swiper-match-face-3 {
+        /* swiper-match-face-3 */
+        color: #DFAF8F;
+        background-color: #2B2B2B;
+        font-weight: bold;
+      }
+      .org-swiper-match-face-4 {
+        /* swiper-match-face-4 */
+        color: #DCDCCC;
+        background-color: #8C5353;
+      }
+      .org-tab-bar {
+        /* tab-bar */
+        color: #000000;
+        background-color: #d9d9d9;
+      }
+      .org-tab-bar-tab {
+        /* tab-bar-tab */
+        color: #000000;
+        background-color: #d9d9d9;
+      }
+      .org-tab-bar-tab-group-current {
+        /* tab-bar-tab-group-current */
+        color: #000000;
+        background-color: #d9d9d9;
+        font-weight: bold;
+      }
+      .org-tab-bar-tab-inactive {
+        /* tab-bar-tab-inactive */
+        color: #000000;
+        background-color: #bfbfbf;
+      }
+      .org-tab-line {
+        /* tab-line */
+        color: #000000;
+        background-color: #d9d9d9;
+        font-size: 90%;
+      }
+      .org-table-cell {
+        /* table-cell */
+        color: #e5e5e5;
+        background-color: #0000ff;
+      }
+      .org-tabulated-list-fake-header {
+        /* tabulated-list-fake-header */
+        font-weight: bold;
+        text-decoration: underline;
+        text-decoration: overline;
+      }
+      .org-terraform--resource-name {
+        /* terraform-resource-name-face */
+        color: #ffc0cb;
+      }
+      .org-terraform--resource-type {
+        /* terraform-resource-type-face */
+        color: #3cb371;
+      }
+      .org-tool-bar {
+        /* tool-bar */
+        color: #000000;
+        background-color: #bfbfbf;
+      }
+      .org-tooltip {
+        /* tooltip */
+        color: #DCDCCC;
+        background-color: #4F4F4F;
+      }
+      .org-trailing-whitespace {
+        /* trailing-whitespace */
+        background-color: #CC9393;
+      }
+      .org-transient-active-infix {
+        /* transient-active-infix */
+        background-color: #5F5F5F;
+      }
+      .org-transient-amaranth {
+        /* transient-amaranth */
+        color: #E52B50;
+        font-weight: bold;
+      }
+      .org-transient-argument {
+        /* transient-argument */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-transient-blue {
+        /* transient-blue */
+        color: #0000ff;
+        font-weight: bold;
+      }
+      .org-transient-disabled-suffix {
+        /* transient-disabled-suffix */
+        color: #000000;
+        background-color: #ff0000;
+        font-weight: bold;
+      }
+      .org-transient-enabled-suffix {
+        /* transient-enabled-suffix */
+        color: #000000;
+        background-color: #00ff00;
+        font-weight: bold;
+      }
+      .org-transient-heading {
+        /* transient-heading */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-transient-inactive-argument {
+        /* transient-inactive-argument */
+        color: #b3b3b3;
+      }
+      .org-transient-inactive-value {
+        /* transient-inactive-value */
+        color: #b3b3b3;
+      }
+      .org-transient-inapt-suffix {
+        /* transient-inapt-suffix */
+        color: #b3b3b3;
+        font-style: italic;
+      }
+      .org-transient-key {
+        /* transient-key */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-transient-mismatched-key {
+        /* transient-mismatched-key */
+        text-decoration: underline;
+      }
+      .org-transient-nonstandard-key {
+        /* transient-nonstandard-key */
+        text-decoration: underline;
+      }
+      .org-transient-pink {
+        /* transient-pink */
+        color: #FF6EB4;
+        font-weight: bold;
+      }
+      .org-transient-red {
+        /* transient-red */
+        color: #ff0000;
+        font-weight: bold;
+      }
+      .org-transient-separator {
+        /* transient-separator */
+        background-color: #4d4d4d;
+      }
+      .org-transient-teal {
+        /* transient-teal */
+        color: #367588;
+        font-weight: bold;
+      }
+      .org-transient-unreachable {
+        /* transient-unreachable */
+        color: #b3b3b3;
+      }
+      .org-transient-unreachable-key {
+        /* transient-unreachable-key */
+        color: #b3b3b3;
+      }
+      .org-transient-value {
+        /* transient-value */
+        color: #CC9393;
+      }
+      .org-treemacs-directory {
+        /* treemacs-directory-face */
+        color: #93E0E3;
+      }
+      .org-treemacs-directory-collapsed {
+        /* treemacs-directory-collapsed-face */
+        color: #93E0E3;
+      }
+      .org-treemacs-file {
+        /* treemacs-file-face */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-treemacs-fringe-indicator {
+        /* treemacs-fringe-indicator-face */
+        color: #000000;
+      }
+      .org-treemacs-git-added {
+        /* treemacs-git-added-face */
+        color: #7CB8BB;
+      }
+      .org-treemacs-git-conflict {
+        /* treemacs-git-conflict-face */
+        color: #ffc0cb;
+        font-weight: bold;
+      }
+      .org-treemacs-git-ignored {
+        /* treemacs-git-ignored-face */
+        color: #7F9F7F;
+      }
+      .org-treemacs-git-modified {
+        /* treemacs-git-modified-face */
+        color: #DFAF8F;
+      }
+      .org-treemacs-git-renamed {
+        /* treemacs-git-renamed-face */
+        color: #9FC59F;
+      }
+      .org-treemacs-git-unmodified {
+        /* treemacs-git-unmodified-face */
+        color: #DCDCCC;
+        background-color: #3F3F3F;
+      }
+      .org-treemacs-git-untracked {
+        /* treemacs-git-untracked-face */
+        color: #CC9393;
+      }
+      .org-treemacs-help-column {
+        /* treemacs-help-column-face */
+        color: #F0DFAF;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-treemacs-help-title {
+        /* treemacs-help-title-face */
+        color: #BFEBBF;
+      }
+      .org-treemacs-on-failure-pulse {
+        /* treemacs-on-failure-pulse-face */
+        color: #111111;
+        background-color: #ab3737;
+      }
+      .org-treemacs-on-success-pulse {
+        /* treemacs-on-success-pulse-face */
+        color: #111111;
+        background-color: #669966;
+      }
+      .org-treemacs-root {
+        /* treemacs-root-face */
+        color: #BFEBBF;
+        font-size: 120%;
+        font-weight: bold;
+        text-decoration: underline;
+      }
+      .org-treemacs-root-remote-unreadable {
+        /* treemacs-root-remote-unreadable-face */
+        color: #BFEBBF;
+        font-size: 120%;
+        font-weight: bold;
+        text-decoration: underline;
+        text-decoration: line-through;
+      }
+      .org-treemacs-root-unreadable {
+        /* treemacs-root-unreadable-face */
+        color: #BFEBBF;
+        font-size: 120%;
+        font-weight: bold;
+        text-decoration: underline;
+        text-decoration: line-through;
+      }
+      .org-treemacs-tags {
+        /* treemacs-tags-face */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-treemacs-term-node {
+        /* treemacs-term-node-face */
+        color: #CC9393;
+      }
+      .org-tty-menu-disabled {
+        /* tty-menu-disabled-face */
+        color: #d3d3d3;
+        background-color: #0000ff;
+      }
+      .org-tty-menu-enabled {
+        /* tty-menu-enabled-face */
+        color: #ffff00;
+        background-color: #0000ff;
+        font-weight: bold;
+      }
+      .org-tty-menu-selected {
+        /* tty-menu-selected-face */
+        background-color: #ff0000;
+      }
+      .org-type {
+        /* font-lock-type-face */
+        color: #7CB8BB;
+      }
+      .org-typescript-access-modifier {
+        /* typescript-access-modifier-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-typescript-jsdoc-tag {
+        /* typescript-jsdoc-tag */
+        color: #708090;
+      }
+      .org-typescript-jsdoc-type {
+        /* typescript-jsdoc-type */
+        color: #4682b4;
+      }
+      .org-typescript-jsdoc-value {
+        /* typescript-jsdoc-value */
+        color: #8b7500;
+      }
+      .org-typescript-primitive {
+        /* typescript-primitive-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-typescript-this {
+        /* typescript-this-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-underline {
+        /* underline */
+        text-decoration: underline;
+      }
+      .org-undo-tree-visualizer-active-branch {
+        /* undo-tree-visualizer-active-branch-face */
+        color: #FFFFEF;
+        font-weight: bold;
+      }
+      .org-undo-tree-visualizer-current {
+        /* undo-tree-visualizer-current-face */
+        color: #BC8383;
+        font-weight: bold;
+      }
+      .org-undo-tree-visualizer-default {
+        /* undo-tree-visualizer-default-face */
+        color: #DCDCCC;
+      }
+      .org-undo-tree-visualizer-register {
+        /* undo-tree-visualizer-register-face */
+        color: #F0DFAF;
+      }
+      .org-undo-tree-visualizer-unmodified {
+        /* undo-tree-visualizer-unmodified-face */
+        color: #93E0E3;
+      }
+      .org-variable-name {
+        /* font-lock-variable-name-face */
+        color: #DFAF8F;
+      }
+      .org-variable-pitch {
+      }
+      .org-vc-annotate-face-5f7f5f {
+        /* vc-annotate-face-5F7F5F */
+        background-color: #5F7F5F;
+      }
+      .org-vc-annotate-face-6ca0a3 {
+        /* vc-annotate-face-6CA0A3 */
+        background-color: #6CA0A3;
+      }
+      .org-vc-annotate-face-7cb8bb {
+        /* vc-annotate-face-7CB8BB */
+        background-color: #7CB8BB;
+      }
+      .org-vc-annotate-face-7f9f7f {
+        /* vc-annotate-face-7F9F7F */
+        background-color: #7F9F7F;
+      }
+      .org-vc-annotate-face-8cd0d3 {
+        /* vc-annotate-face-8CD0D3 */
+        background-color: #8CD0D3;
+      }
+      .org-vc-annotate-face-8fb28f {
+        /* vc-annotate-face-8FB28F */
+        background-color: #8FB28F;
+      }
+      .org-vc-annotate-face-93e0e3 {
+        /* vc-annotate-face-93E0E3 */
+        background-color: #93E0E3;
+      }
+      .org-vc-annotate-face-94bff3 {
+        /* vc-annotate-face-94BFF3 */
+        background-color: #94BFF3;
+      }
+      .org-vc-annotate-face-9fc59f {
+        /* vc-annotate-face-9FC59F */
+        background-color: #9FC59F;
+      }
+      .org-vc-annotate-face-afd8af {
+        /* vc-annotate-face-AFD8AF */
+        background-color: #AFD8AF;
+      }
+      .org-vc-annotate-face-bc8383 {
+        /* vc-annotate-face-BC8383 */
+        background-color: #BC8383;
+      }
+      .org-vc-annotate-face-bfebbf {
+        /* vc-annotate-face-BFEBBF */
+        background-color: #BFEBBF;
+      }
+      .org-vc-annotate-face-cc9393 {
+        /* vc-annotate-face-CC9393 */
+        background-color: #CC9393;
+      }
+      .org-vc-annotate-face-d0bf8f {
+        /* vc-annotate-face-D0BF8F */
+        background-color: #D0BF8F;
+      }
+      .org-vc-annotate-face-dc8cc3 {
+        /* vc-annotate-face-DC8CC3 */
+        background-color: #DC8CC3;
+      }
+      .org-vc-annotate-face-dfaf8f {
+        /* vc-annotate-face-DFAF8F */
+        background-color: #DFAF8F;
+      }
+      .org-vc-annotate-face-e0cf9f {
+        /* vc-annotate-face-E0CF9F */
+        background-color: #E0CF9F;
+      }
+      .org-vc-annotate-face-f0dfaf {
+        /* vc-annotate-face-F0DFAF */
+        background-color: #F0DFAF;
+      }
+      .org-vc-conflict-state {
+      }
+      .org-vc-dir-directory {
+        /* vc-dir-directory */
+        color: #5F7F5F;
+      }
+      .org-vc-dir-file {
+        /* vc-dir-file */
+        color: #93E0E3;
+      }
+      .org-vc-dir-header {
+        /* vc-dir-header */
+        color: #7CB8BB;
+      }
+      .org-vc-dir-header-value {
+        /* vc-dir-header-value */
+        color: #DFAF8F;
+      }
+      .org-vc-dir-mark-indicator {
+        /* vc-dir-mark-indicator */
+        color: #7CB8BB;
+      }
+      .org-vc-dir-status-edited {
+        /* vc-dir-status-edited */
+        color: #DFAF8F;
+      }
+      .org-vc-dir-status-ignored {
+        /* vc-dir-status-ignored */
+        color: #b3b3b3;
+      }
+      .org-vc-dir-status-up-to-date {
+        /* vc-dir-status-up-to-date */
+        color: #DCDCCC;
+        font-weight: bold;
+      }
+      .org-vc-dir-status-warning {
+        /* vc-dir-status-warning */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-vc-edited-state {
+      }
+      .org-vc-locally-added-state {
+      }
+      .org-vc-locked-state {
+      }
+      .org-vc-missing-state {
+      }
+      .org-vc-needs-update-state {
+      }
+      .org-vc-removed-state {
+      }
+      .org-vc-state-base {
+      }
+      .org-vc-up-to-date-state {
+      }
+      .org-vertical-border {
+        /* vertical-border */
+        color: #DCDCCC;
+      }
+      .org-volume-bar {
+        /* volume-bar */
+        font-weight: bold;
+      }
+      .org-warning {
+        /* warning */
+        color: #DFAF8F;
+        font-weight: bold;
+      }
+      .org-warning-1 {
+        /* font-lock-warning-face */
+        color: #D0BF8F;
+        font-weight: bold;
+      }
+      .org-wgrep {
+        /* wgrep-face */
+        color: #000000;
+        background-color: #c6e2ff;
+      }
+      .org-wgrep-delete {
+        /* wgrep-delete-face */
+        color: #ffc0cb;
+        background-color: #c6e2ff;
+      }
+      .org-wgrep-done {
+        /* wgrep-done-face */
+        color: #87cefa;
+      }
+      .org-wgrep-file {
+        /* wgrep-file-face */
+        color: #ffffff;
+        background-color: #4d4d4d;
+      }
+      .org-wgrep-reject {
+        /* wgrep-reject-face */
+        color: #ff69b4;
+        font-weight: bold;
+      }
+      .org-which-func {
+        /* which-func */
+        color: #BFEBBF;
+      }
+      .org-which-key-command-description {
+        /* which-key-command-description-face */
+        color: #93E0E3;
+      }
+      .org-which-key-docstring {
+        /* which-key-docstring-face */
+        color: #7F9F7F;
+      }
+      .org-which-key-group-description {
+        /* which-key-group-description-face */
+        color: #F0DFAF;
+        font-weight: bold;
+      }
+      .org-which-key-highlighted-command {
+        /* which-key-highlighted-command-face */
+        color: #93E0E3;
+        text-decoration: underline;
+      }
+      .org-which-key-key {
+        /* which-key-key-face */
+        color: #BFEBBF;
+      }
+      .org-which-key-local-map-description {
+        /* which-key-local-map-description-face */
+        color: #93E0E3;
+      }
+      .org-which-key-note {
+        /* which-key-note-face */
+        color: #7F9F7F;
+      }
+      .org-which-key-separator {
+        /* which-key-separator-face */
+        color: #7F9F7F;
+      }
+      .org-which-key-special-key {
+        /* which-key-special-key-face */
+        color: #BFEBBF;
+        font-weight: bold;
+      }
+      .org-whitespace-big-indent {
+        /* whitespace-big-indent */
+        color: #b22222;
+        background-color: #ff0000;
+      }
+      .org-whitespace-empty {
+        /* whitespace-empty */
+        background-color: #F0DFAF;
+      }
+      .org-whitespace-hspace {
+        /* whitespace-hspace */
+        color: #4F4F4F;
+        background-color: #4F4F4F;
+      }
+      .org-whitespace-indentation {
+        /* whitespace-indentation */
+        color: #CC9393;
+        background-color: #F0DFAF;
+      }
+      .org-whitespace-line {
+        /* whitespace-line */
+        color: #DC8CC3;
+        background-color: #3F3F3F;
+      }
+      .org-whitespace-missing-newline-at-eof {
+        /* whitespace-missing-newline-at-eof */
+        color: #000000;
+        background-color: #d0d040;
+      }
+      .org-whitespace-newline {
+        /* whitespace-newline */
+        color: #4F4F4F;
+      }
+      .org-whitespace-space {
+        /* whitespace-space */
+        color: #4F4F4F;
+        background-color: #4F4F4F;
+      }
+      .org-whitespace-space-after-tab {
+        /* whitespace-space-after-tab */
+        color: #CC9393;
+        background-color: #F0DFAF;
+      }
+      .org-whitespace-space-before-tab {
+        /* whitespace-space-before-tab */
+        color: #DFAF8F;
+        background-color: #DFAF8F;
+      }
+      .org-whitespace-tab {
+        /* whitespace-tab */
+        background-color: #BC8383;
+      }
+      .org-whitespace-trailing {
+        /* whitespace-trailing */
+        background-color: #CC9393;
+      }
+      .org-widget-button {
+        /* widget-button */
+        font-weight: bold;
+      }
+      .org-widget-button-pressed {
+        /* widget-button-pressed */
+        color: #ff0000;
+      }
+      .org-widget-documentation {
+        /* widget-documentation */
+        color: #32cd32;
+      }
+      .org-widget-field {
+        /* widget-field */
+        color: #DCDCCC;
+        background-color: #6F6F6F;
+      }
+      .org-widget-inactive {
+        /* widget-inactive */
+        color: #b3b3b3;
+      }
+      .org-widget-single-line-field {
+        /* widget-single-line-field */
+        background-color: #696969;
+      }
+      .org-window-divider {
+        /* window-divider */
+        color: #999999;
+      }
+      .org-window-divider-first-pixel {
+        /* window-divider-first-pixel */
+        color: #cccccc;
+      }
+      .org-window-divider-last-pixel {
+        /* window-divider-last-pixel */
+        color: #666666;
+      }
+      .org-window-number {
+        /* window-number-face */
+        color: #ffffff;
+        background-color: #8b0000;
+      }
+      .org-xref-file-header {
+        /* xref-file-header */
+        color: #BFEBBF;
+        text-decoration: underline;
+      }
+      .org-xref-line-number {
+        /* xref-line-number */
+        color: #F0DFAF;
+      }
+      .org-xref-match {
+        /* xref-match */
+        background-color: #383838;
+      }
+      .org-yaml-tab {
+        /* yaml-tab-face */
+        color: #ff0000;
+        background-color: #ff0000;
+        font-weight: bold;
+      }
+      .org-yas--field-debug {
+      }
+      .org-yas-field-highlight {
+        /* yas-field-highlight-face */
+        background-color: #2B2B2B;
+      }
+
+      /* a { */
+      /*   color: inherit; */
+      /*   background-color: inherit; */
+      /*   font: inherit; */
+      /*   text-decoration: inherit; */
+      /* } */
+
+      a:hover {
+        text-decoration: underline;
+      }
+    -->
+</style>
