#!/usr/bin/env bash
# this is an auto generated file. do not edit manually
{
    
# wizard configuration file

if test -e ~/.wizardrc; then
  source ~/.wizardrc

else
  export BROWSER="google-chrome"
  export DNSSERVER="8.8.8.8"
fi
cloudflare::fetch-zone () 
{ 
    cloudflare::request GET zones | python3 -c '
import json
import sys
from apocrypha.client import Client

data = json.load(sys.stdin)
zone = data.get("result", [None])[0]
Client().set("wizard", "cloudflare", "zones", value=zone)
'
}
cloudflare::purge () 
{ 
    local zone;
    zone="$( d wizard cloudflare zones id )";
    [[ -n $zone ]] || { 
        cloudflare::fetch-zone;
        zone="$( d wizard cloudflare zones id )"
    };
    [[ -n $zone ]] || common::error "Couldn't find the Zone ID";
    cloudflare::request POST zones/"$zone"/purge_cache --data '{"purge_everything":true}'
}
cloudflare::request () 
{ 
    method="$1";
    target="$2";
    shift;
    shift;
    case "$target" in 
        https://*)

        ;;
        *)
            target="https://api.cloudflare.com/client/v4/$target"
        ;;
    esac;
    local token;
    token="$( d wizard cloudflare token )";
    [[ -n $token ]] || common::error "Need token at: wizard cloudflare token";
    curl --silent -X "$method" "$target" -H "Authorization: Bearer $token" -H "Content-Type:application/json" "$@"
}
common::cd () 
{ 
    local target="$1";
    if [[ "$target" == "$(pwd)" ]]; then
        return;
    fi;
    ECHO=0 common::do cd "$target"
}
common::check-network () 
{ 
    common::verify-global "DNSSERVER";
    nc -w 1 -z "$DNSSERVER" 53 > /dev/null 2>&1
}
common::choice () 
{ 
    items=("$@");
    echo "${items[$RANDOM % ${#items[@]} ]}"
}
common::clone () 
{ 
    local target="${1?target required}";
    local location="${2?location required}";
    [[ -d "$location" ]] || common::error "location doesn't exist!";
    common::do git clone --depth 1 "$target" "$location"
}
common::color-error () 
{ 
    QUIET=0 common::echo "$@";
    exit 1
}
common::confirm () 
{ 
    if ! (( "$AUTO" )); then
        common::echo-n "$* [yN] ";
        read -r reply;
        [[ "$reply" =~ [Nn] ]] && exit 1;
    fi;
    true
}
common::contains () 
{ 
    [[ $1 =~ $2 ]]
}
common::debug () 
{ 
    (( "$DEBUG" )) && eval "$*"
}
common::dir-exists () 
{ 
    [[ -d "$1" ]]
}
common::do () 
{ 
    if (( "$CONFIRM" )); then
        common::echo "Continue? [Yn]";
        read -r reply;
        [[ "$reply" =~ [Nn] ]] && exit 1;
    fi;
    if (( "$ECHO" )); then
        common::echo "$*";
    else
        if (( "$QUIET" )); then
            eval "${@/ \"\"/}" || common::color-error "error running \"$*\"";
        else
            if (( "$SILENT" )); then
                eval "${@/ \"\"/}" > /dev/null 2> /dev/null || common::color-error "error running \"$*\"";
            else
                if (( "$IGNORE" )); then
                    eval "${@/ \"\"/}";
                else
                    common::echo "$*";
                    eval "${@/ \"\"/}" || common::color-error "error running \"$*\"";
                fi;
            fi;
        fi;
    fi
}
common::echo () 
{ 
    (( QUIET )) || { 
        local green="\033[01;32m" normal="\033[00m";
        printf "%b%s%b"\\n "$green" "$*" "$normal"
    }
}
common::echo-n () 
{ 
    (( QUIET )) || { 
        local green="\033[01;32m" normal="\033[00m";
        printf "%b%s%b" "$green" "$*" "$normal"
    }
}
common::error () 
{ 
    echo "$*" 1>&2;
    exit 1
}
common::file-exists () 
{ 
    [[ -f "$1" ]]
}
common::file-not-empty () 
{ 
    [[ -s "$1" ]]
}
common::filterl () 
{ 
    [[ -n $1 ]] || return;
    common::mapl "$* && echo {}"
}
common::for () 
{ 
    while [[ -n $1 ]]; do
        echo "$1";
        shift;
    done
}
common::inplace-file-op () 
{ 
    local file="$1";
    shift;
    local copy="$file".copy;
    local ops="$*";
    mv "$file" "$copy";
    eval "cat $copy | $ops > $file";
    local code=$?;
    rm "$copy";
    return $code
}
common::is-integer () 
{ 
    [ "$1" -eq "$1" ] 2> /dev/null
}
common::join () 
{ 
    tr '\n' ' ';
    echo
}
common::map () 
{ 
    local __items=();
    local __item;
    while read -r __item; do
        __items+=("$__item");
    done;
    [[ -n ${__items[*]} ]] || exit 1;
    for __item in "${__items[@]}";
    do
        "$@" "$__item";
    done
}
common::mapl () 
{ 
    [[ -n $1 ]] || return;
    eval "
  __lambda() {
    ${*//\{\}/\"\$1\"}
  }
  ";
    common::map __lambda
}
common::maybe-filter () 
{ 
    [[ -n $1 ]] && grep "$1";
    cat
}
common::mmap () 
{ 
    local __items=();
    local __item;
    while read -r __item; do
        __items+=("$__item");
    done;
    local __tmpdir=/dev/shm;
    [[ -e "$__tmpdir" ]] || __tmpdir=/tmp;
    local __tmps=();
    for __item in "${__items[@]}";
    do
        __tmp="$(mktemp "$__tmpdir"/mmap.XXXXXXXXXXXXXXXXXXXXXX)";
        __tmps+=("$__tmp");
        "$@" "$__item" > "$__tmp" 2>&1 &
    done;
    wait;
    for __tmp in "${__tmps[@]}";
    do
        cat "$__tmp";
        rm -f "$__tmp";
    done
}
common::multi-menu () 
{ 
    fzf --reverse --cycle --multi "$@"
}
common::open-file () 
{ 
    "${EDITOR:-vim}" "$@"
}
common::open-link () 
{ 
    common::verify-global "BROWSER";
    "$BROWSER" "$1" 2> /dev/null > /dev/null &
}
common::optional-help () 
{ 
    local caller="${FUNCNAME[1]//_/ }";
    case $1 in 
        -h | --help)
            common::error "
${caller} ${*:2}"
        ;;
    esac
}
common::pip () 
{ 
    common::do python3 -m pip "$*"
}
common::process-exists () 
{ 
    kill -0 "$1"
}
common::program-exists () 
{ 
    command -v "$1" > /dev/null 2> /dev/null
}
common::quick () 
{ 
    common::optional-help "$1" "(--global) (--add|--del|--edit) [name] [command]

  manage and run dynamic commands specific to the current context. commands are
  stored in the remote database accessed with 'd'.

  --add    <name> <command ...> create a new quick command
  --del    <name>               delete a quick command
  --edit   <name>               edit a quick command with \$EDITOR
  --rename <old> <new>          rename a quick command
  --copy   <context>            copy quick commands from somewhere else
  <name ...>                    run one or more quick commands
  ''                            lists currently available quick commands

  q --add b stack build
  q b
  q
  q --del b
  ";
    [[ -n $QUICK_CONTEXT ]] || common::error "programming error: \$QUICK_CONTEXT not defined";
    local context;
    context="$( d current-context )";
    local global='';
    local verbose=0;
    while [[ -n $1 ]]; do
        case "$1" in 
            -g | --global)
                context="$QUICK_CONTEXT";
                global='global ';
                shift
            ;;
            -v | --verbose)
                verbose=1;
                shift
            ;;
            *)
                break
            ;;
        esac;
    done;
    case "$1" in 
        -a | --add)
            local action=add;
            local name="$2";
            local cmd="${*:3}";
            [[ -n $name ]] || common::error "no name provided";
            [[ -n $cmd ]] || common::error "no command provided"
        ;;
        -d | --del)
            local action=del;
            local name="$2";
            [[ -n $name ]] || common::error "no name provided"
        ;;
        -e | --edit)
            local action=edit;
            local name="$2";
            [[ -n $name ]] || common::error "no name provided"
        ;;
        -c | --copy)
            local action=copy;
            local other="${*:2}";
            [[ -n $other ]] || common::error "no other context provided"
        ;;
        -r | --rename)
            local action=rename;
            local old="$2";
            local new="$3";
            [[ -n $old && -n $new ]] || common::error "<old> and <new> must be provided"
        ;;
        --clone)
            local action=clone;
            local name="$2";
            [[ -n $name ]] || common::error "no name provided"
        ;;
        *)
            action=run
        ;;
    esac;
    [[ -n $1 ]] || action=list;
    case $action in 
        add)
            d "$context" quick "$QUICK_CONTEXT" "$name" = "$cmd"
        ;;
        del)
            d "$context" quick "$QUICK_CONTEXT" "$name" --del
        ;;
        edit)
            local tmp;
            tmp="$( mktemp )";
            d "$context" quick "$QUICK_CONTEXT" "$name" > "$tmp";
            "${EDITOR:-vi}" "$tmp";
            d "$context" quick "$QUICK_CONTEXT" "$name" = "$( cat "$tmp" )";
            rm "$tmp"
        ;;
        copy)
            function copy () 
            { 
                local name="$1";
                d "$context" quick "$QUICK_CONTEXT" "$name" = "$(
          d "$other" quick "$QUICK_CONTEXT" "$name"
        )"
            };
            d "$other" quick "$QUICK_CONTEXT" --keys | common::multi-menu --preview "d '$other' quick '$QUICK_CONTEXT' {}" --preview-window up | common::map copy
        ;;
        rename)
            local cmd=/tmp/quick-command;
            trap 'rm -f $cmd' EXIT;
            d "$context" quick "$QUICK_CONTEXT" "$old" --edit > "$cmd";
            d "$context" quick "$QUICK_CONTEXT" "$new" --set "$( tr -d '\n' < "$cmd" )";
            d "$context" quick "$QUICK_CONTEXT" "$old" --del
        ;;
        clone)
            function assign () 
            { 
                local source="$1";
                d "$context" quick "$QUICK_CONTEXT" "$name" = "$(
          d "$context" quick "$QUICK_CONTEXT" "$source"
        )"
            };
            d "$context" quick "$QUICK_CONTEXT" --keys | common::single-menu --preview "d !current-context quick '$QUICK_CONTEXT' {}" --preview-window up | common::map assign;
            common::quick --edit "$name"
        ;;
        list)
            d "$context" quick "$QUICK_CONTEXT" | python -c '
import json
import sys

verbose = sys.argv[1] == "1"
def tidy(s):
  if not verbose and len(s) > 90:
    s = s[:87] + "..."
  return s

try:
  data = json.load(sys.stdin)
except:
  print("no quick commands available for '"$QUICK_CONTEXT"' namespace")
  sys.exit(0)

print("")
for k, v in sorted(data.items()):
  if isinstance(v, list):
    print("{k: >10}".format(k=k))
    for e in v:
      print("{k: >10}   {e}".format(k="", e=tidy(e)))
    print("")
  else:
    print("{k: >10}   {v}".format(k=k, v=tidy(v)))
print("")
      ' "$verbose"
        ;;
        run)
            function find_and_run () 
            { 
                local name="$1";
                local cmd;
                cmd="$(
          d "$context" quick "$QUICK_CONTEXT" "$name" | grep . ||
            d "$QUICK_CONTEXT" quick "$QUICK_CONTEXT" "$name"
        )";
                [[ -n $cmd ]] || common::error "couldn't find a command for $name in $global$QUICK_CONTEXT namespace";
                common::echo "$cmd";
                eval "$cmd"
            };
            common::for "$@" | common::map find_and_run
        ;;
        *)
            common::error "programming error"
        ;;
    esac
}
common::require () 
{ 
    local caller="${FUNCNAME[1]//_/ }";
    local force=0;
    while [[ -n $1 ]]; do
        case $1 in 
            -f)
                force=1
            ;;
            *)
                common::program-exists "$1" || { 
                    if (( force )); then
                        common::error "Need $1 to continue with $caller";
                    else
                        return 1;
                    fi
                }
            ;;
        esac;
        shift;
    done
}
common::required-help () 
{ 
    local caller="${FUNCNAME[1]//_/ }";
    case $1 in 
        '' | -h | --help)
            common::error "
${caller} ${*:2}"
        ;;
    esac
}
common::return () 
{ 
    return "$1"
}
common::rocmap () 
{ 
    local size="$1";
    local running=0;
    shift;
    local __items=();
    local __item;
    while read -r __item; do
        __items+=("$__item");
    done;
    local __tmpdir=/dev/shm;
    [[ -e "$__tmpdir" ]] || __tmpdir=/tmp;
    local __tmps=();
    for __item in "${__items[@]}";
    do
        __tmp="$( mktemp "$__tmpdir"/mmap.XXXXXXXXXXXXXXXXXXXXXX )";
        __tmps+=("$__tmp");
        "$@" "$__item" > "$__tmp" 2>&1 & (( running++ ));
        while (( running > size )); do
            sleep 0.1;
            running="$( jobs -p | wc -l )";
        done;
    done;
    wait;
    for __tmp in "${__tmps[@]}";
    do
        cat "$__tmp";
        rm -f "$__tmp";
    done
}
common::rucmap () 
{ 
    local size="$1";
    local running=0;
    shift;
    local __items=();
    local __item;
    while read -r __item; do
        __items+=("$__item");
    done;
    [[ -n ${__items[*]} ]] || exit 1;
    for __item in "${__items[@]}";
    do
        "$@" "$__item" & (( running++ ));
        while (( running > size )); do
            sleep 0.1;
            running="$( jobs -p | wc -l )";
        done;
    done;
    wait
}
common::sed () 
{ 
    if common::program-exists gsed; then
        gsed "$@";
    else
        sed "$@";
    fi
}
common::single-menu () 
{ 
    fzf --reverse --cycle "$@"
}
common::sleep () 
{ 
    local amount="$1";
    local index=0;
    while (( index < amount )); do
        echo -en "\rsleeping ($index/$amount)...";
        sleep 1;
        (( index++ ));
    done;
    echo
}
common::sudo () 
{ 
    common::do "sudo" "$@"
}
common::symlink-exists () 
{ 
    [[ -L "$1" ]]
}
common::translate-time () 
{ 
    local time="$1";
    if (( time <= 60 )); then
        echo "$time seconds";
    else
        if (( time <= 3600 )); then
            echo "$(( time / 60 )) minutes";
        else
            if (( time <= 86400 )); then
                echo "$(( time / 3600 )) hours";
            else
                echo "$(( time / 86400 )) days";
            fi;
        fi;
    fi
}
common::try-json-parse () 
{ 
    if common::dir-exists /dev/shm; then
        local tmp=/dev/shm/;
    else
        local tmp=/tmp/;
    fi;
    tmp+=json-parse-$RANDOM$RANDOM$RANDOM;
    cat - > "$tmp";
    python -m json.tool < "$tmp" 2> /dev/null || cat "$tmp";
    rm "$tmp"
}
common::verify-global () 
{ 
    local global="$1";
    [[ -n ${!global} ]] || common::error "$global not defined in ~/.wizardrc.

  run \"wizard help ${global//_/-}\" for more information
  "
}
common::wait-until () 
{ 
    while eval "$@" > /dev/null 2> /dev/null; do
        sleep 1;
        echo -n ".";
    done;
    echo -n " Done!";
    echo
}
db::get () 
{ 
    local variable="$1";
    shift;
    mapfile -t "${variable?}" < <(d "$@")
}
devbot::debug () 
{ 
    [[ -n $debug ]] || return;
    printf '%s - %s - %s\n' "$(date +'%x %X')" "${FUNCNAME[1]}" "$*"
}
devbot::eval () 
{ 
    local -r name="$1";
    shift;
    local -r lockfile=~/.devbot/locks/"$name".lock;
    { 
        local -r begin="$(date '+%s')";
        devbot::debug "$*";
        if flock --nonblock --exclusive "$lockfile" bash -c "set -e; $*"; then
            if [[ -n $(d devbot data "$name" errors) ]]; then
                d devbot data "$name" errors -d;
            fi;
        else
            local -i errors="$(d devbot data "$name" errors)";
            errors+=1;
            d devbot data "$name" errors = "$errors";
            local -r backoff="$(bc <<< "$errors * 10 ^ 2 / 1")";
            local -r when="$(d devbot data "$name" when)";
            d devbot data "$name" when = "$(( when + backoff ))";
            devbot::log "error while running \"$name\" ($*), backing off $backoff seconds";
        fi;
        local -r end="$(date '+%s')";
        d devbot data "$name" duration = "$(( end - begin ))"
    } & disown
}
devbot::log () 
{ 
    printf '%s - %s - %s\n' "$(date +'%x %X')" "${FUNCNAME[1]}" "$*"
}
devbot::main () 
{ 
    mkdir -p ~/.devbot/locks/;
    devbot::log "starting devbot";
    while :; do
        local debug="$(d devbot debug)";
        local now="$(date '+%s')";
        devbot::debug "reading events";
        d devbot events --keys | common::map devbot::task;
        sleep 5;
    done
}
devbot::task () 
{ 
    devbot::debug "$*";
    local -r event="$1";
    local -r when="$(d devbot data "$event" when)";
    if (( when < now )); then
        local -r req_name="$(d devbot events "$event" require)";
        if [[ -n $req_name ]]; then
            local -r req_action="$(d devbot requirements "$req_name")";
            if ! eval "$req_action"; then
                devbot::log "$event requirement \"$req_name\" ($req_action) not met";
                return;
            fi;
        fi;
        local interval="$(d devbot events "$event" interval)";
        case $interval in 
            [0-9]*)

            ;;
            daily)
                interval=86400
            ;;
            hourly)
                interval=3600
            ;;
            weekly)
                interval=604800
            ;;
            '')
                devbot::log "::task error: $event has no interval";
                return
            ;;
            *)
                devbot::log "::task error: $event has invalid interval";
                return
            ;;
        esac;
        d devbot data "$event" when = $(( interval + now ));
        local -r action="$(d devbot events "$event" action)";
        [[ -n $action ]] || { 
            devbot::log "::task error: $event has no action";
            return
        };
        devbot::eval "$event" "$action";
    fi
}
git::ahead-of-master () 
{ 
    local msg='Your branch is ahead of';
    grep -q "$msg" <<< "$(git status)"
}
git::branch-exists () 
{ 
    local branch="$1";
    git rev-parse --verify "$branch" > /dev/null 2>&1
}
git::can-fastforward () 
{ 
    local msg='can be fast-forwarded';
    grep -q "$msg" <<< "$(git status)"
}
git::commit-exists () 
{ 
    local target="$1";
    grep -q "$target" <<< "$(git log --oneline | head -n 1)"
}
git::current-branch () 
{ 
    git rev-parse --abbrev-ref HEAD
}
git::have-diverged () 
{ 
    local msg='have diverged';
    grep -q "$msg" <<< "$(git status)"
}
git::is-clean () 
{ 
    local msg='nothing to commit, working .* clean';
    grep -q "$msg" <<< "$(git status)"
}
git::is-dirty () 
{ 
    local msg='Changes not staged for commit';
    grep -q "$msg" <<< "$(git status)"
}
http::docker () 
{ 
    local port="${1:-8080}";
    docker run -it --rm -p "$port":80 -v "$( pwd )":/usr/share/nginx/html nginx
}
media::create () 
{ 
    local name="$1";
    local data="$2";
    common::program-exists -f 'convert';
    common::cd ~/working/object-publish/"$name"-web;
    common::do bash ~/google_drive/code/shell/"$name"/runner.sh /mnt/zfs/Media/Pictures/"$data"/
}
media::sync () 
{ 
    local name="$1";
    rsync -avL --delete ~/working/object-publish/"$name"-web/ walnut:local/"$name"-web
}
wizard () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  clean ...
  configure ...
  execute ...
  git ...
  hunt
  install ...
  make ...
  media ...
  parse ...
  regenerate
  show ...
  start ...
  switch
  transcode ...
  update ..." __name="wizard";
    common::required-help "$1" "(-q | -s | -e)
$__usage
";
    case $OSTYPE in 
        linux*)
            NUM_CPUS="$( getconf _NPROCESSORS_ONLN )"
        ;;
        *bsd*)
            NUM_CPUS="$( sysctl -n hw.ncpu )"
        ;;
    esac;
    [[ -n $NUM_CPUS ]] || NUM_CPUS=4;
    while [[ -n $1 ]]; do
        case $1 in 
            -q | --quiet)
                QUIET=1
            ;;
            -s | --silent)
                SILENT=1
            ;;
            -e | --echo)
                ECHO=1
            ;;
            "c" | "cl" | "cle" | "clea" | "clean")
                wizard_clean "${@:2}";
                exit $?
            ;;
            "c" | "co" | "con" | "conf" | "confi" | "config" | "configu" | "configur" | "configure")
                wizard_configure "${@:2}";
                exit $?
            ;;
            "e" | "ex" | "exe" | "exec" | "execu" | "execut" | "execute")
                wizard_execute "${@:2}";
                exit $?
            ;;
            "g" | "gi" | "git")
                wizard_git "${@:2}";
                exit $?
            ;;
            "h" | "hu" | "hun" | "hunt")
                wizard_hunt "${@:2}";
                exit $?
            ;;
            "i" | "in" | "ins" | "inst" | "insta" | "instal" | "install")
                wizard_install "${@:2}";
                exit $?
            ;;
            "m" | "ma" | "mak" | "make")
                wizard_make "${@:2}";
                exit $?
            ;;
            "m" | "me" | "med" | "medi" | "media")
                wizard_media "${@:2}";
                exit $?
            ;;
            "p" | "pa" | "par" | "pars" | "parse")
                wizard_parse "${@:2}";
                exit $?
            ;;
            "r" | "re" | "reg" | "rege" | "regen" | "regene" | "regener" | "regenera" | "regenerat" | "regenerate")
                wizard_regenerate "${@:2}";
                exit $?
            ;;
            "s" | "sh" | "sho" | "show")
                wizard_show "${@:2}";
                exit $?
            ;;
            "s" | "st" | "sta" | "star" | "start")
                wizard_start "${@:2}";
                exit $?
            ;;
            "s" | "sw" | "swi" | "swit" | "switc" | "switch")
                wizard_switch "${@:2}";
                exit $?
            ;;
            "t" | "tr" | "tra" | "tran" | "trans" | "transc" | "transco" | "transcod" | "transcode")
                wizard_transcode "${@:2}";
                exit $?
            ;;
            "u" | "up" | "upd" | "upda" | "updat" | "update")
                wizard_update "${@:2}";
                exit $?
            ;;
            __list)
                echo clean configure execute git hunt install make media parse regenerate show start switch transcode update
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard::apt () 
{ 
    common::required-help "$1" "[package...]

  install a package with apt
  ";
    common::sudo apt install -y "$@"
}
wizard::file-equal () 
{ 
    local first second;
    first="$( sha1sum "$1" | awk '{print $1}' )";
    second="$( sha1sum "$2" | awk '{print $1}' )";
    [[ "$first" == "$second" ]]
}
wizard::upload () 
{ 
    [[ -n $config ]] || common::error "programming error";
    common::do s3cmd sync -c "$config" --acl-public --delete-removed --exclude-from ~/working/config/s3cmd-exclude --follow-symlinks --guess-mime-type --no-mime-magic --recursive "$1" s3://anardil-public/share/
}
wizard_clean () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  apt
  boot
  docker ...
  every-other
  files
  git ...
  haskell" __name="wizard clean";
    while [[ -n $1 ]]; do
        case $1 in 
            "a" | "ap" | "apt")
                wizard_clean_apt "${@:2}";
                exit $?
            ;;
            "b" | "bo" | "boo" | "boot")
                wizard_clean_boot "${@:2}";
                exit $?
            ;;
            "d" | "do" | "doc" | "dock" | "docke" | "docker")
                wizard_clean_docker "${@:2}";
                exit $?
            ;;
            "e" | "ev" | "eve" | "ever" | "every" | "every-" | "every-o" | "every-ot" | "every-oth" | "every-othe" | "every-other" | "eo")
                wizard_clean_every-other "${@:2}";
                exit $?
            ;;
            "f" | "fi" | "fil" | "file" | "files")
                wizard_clean_files "${@:2}";
                exit $?
            ;;
            "g" | "gi" | "git")
                wizard_clean_git "${@:2}";
                exit $?
            ;;
            "h" | "ha" | "has" | "hask" | "haske" | "haskel" | "haskell")
                wizard_clean_haskell "${@:2}";
                exit $?
            ;;
            __list)
                echo apt boot docker every-other files git haskell
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_clean_apt () 
{ 
    common::optional-help "$1" "

  force purge removed apt packages. this will remove configuration files too.
  ";
    dpkg --list | grep "^rc" | cut -d " " -f 3 | xargs sudo dpkg --purge || common::color-error "Looks like there's nothing to clean!"
}
wizard_clean_boot () 
{ 
    common::optional-help "$1" "

  safely cleans up old Linux kernel versions from /boot
  ";
    dpkg --list | grep linux-image | awk '{ print $2 }' | sort -V | common::sed -n '/'"$(uname -r)"'/q;p' | xargs sudo apt-get -y purge
}
wizard_clean_docker () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  containers
  images" __name="wizard clean docker";
    while [[ -n $1 ]]; do
        case $1 in 
            "c" | "co" | "con" | "cont" | "conta" | "contai" | "contain" | "containe" | "container" | "containers")
                wizard_clean_docker_containers "${@:2}";
                exit $?
            ;;
            "i" | "im" | "ima" | "imag" | "image" | "images")
                wizard_clean_docker_images "${@:2}";
                exit $?
            ;;
            __list)
                echo containers images
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_clean_docker_containers () 
{ 
    common::optional-help "$1" "(--force)

  select docker containers for deletion
  ";
    case $1 in 
        -f | --force)
            function remove () 
            { 
                docker rm --force "$@"
            }
        ;;
        *)
            function remove () 
            { 
                docker rm "$@"
            }
        ;;
    esac;
    docker ps -a | common::multi-menu | awk '{ print $1 }' | common::map remove
}
wizard_clean_docker_images () 
{ 
    common::optional-help "$1" "(--force)

  select docker images for deletion
  ";
    case $1 in 
        -f | --force)
            function remove () 
            { 
                docker image rm --force "$@"
            }
        ;;
        *)
            function remove () 
            { 
                docker image rm "$@"
            }
        ;;
    esac;
    docker images | common::multi-menu | awk '{ print $3 }' | common::map remove
}
wizard_clean_every-other () 
{ 
    common::optional-help "$1" "

  delete every other file in the current directory
  ";
    local delete=0;
    for file in *;
    do
        (( delete )) && common::do rm -v "$file";
        delete=$(( ! delete ));
    done
}
wizard_clean_files () 
{ 
    common::optional-help "$1" "[--dry]

  smart remove duplicate file names and intermediary file types

    clean up the filesystem under the current directory, mostly useful for
    removing duplicate files insync creates
  ";
    local dry=0;
    local counter=0;
    case $1 in 
        -d | --dry)
            dry=1
        ;;
    esac;
    function run () 
    { 
        echo "$@";
        if (( ! dry )); then
            "$@" || { 
                common::error "unexpected failure while running $*"
            };
        fi;
        (( counter++ ))
    };
    while read -r duplicated_path; do
        local fixed_path;
        fixed_path="$(
      # shellcheck disable=SC2001
      common::sed -e 's/[ ]*([0-9]\+)//' <<< "$duplicated_path"
    )";
        [[ -e "$duplicated_path" ]] || continue;
        if [[ -f "$fixed_path" ]]; then
            fixed_path_time="$( stat -c '%Y' "$fixed_path" )";
            duplicate_time="$( stat -c '%Y' "$duplicated_path" )";
            if (( duplicate_time < fixed_path_time )); then
                run rm "$duplicated_path";
            else
                run mv "$duplicated_path" "$fixed_path";
            fi;
        else
            if [[ -d "$fixed_path" ]]; then
                fixed_path_time="$( stat -c '%Y' "$fixed_path" )";
                duplicate_time="$( stat -c '%Y' "$duplicated_path" )";
                if (( duplicate_time < fixed_path_time )); then
                    run rm "$duplicated_path";
                else
                    run mv "$duplicated_path" "$fixed_path";
                fi;
            else
                run mv "$duplicated_path" "$fixed_path";
            fi;
        fi;
    done < <(find . -regex '.*([0-9]+).*');
    while read -r file; do
        run rm "$file";
    done < <(find . -regex '.*\.\(pyc\|class\|o\|bak\)');
    if (( dry )); then
        common::echo "Would have cleaned up $counter files";
    else
        common::echo "Cleaned up $counter files";
    fi
}
wizard_clean_git () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  branches" __name="wizard clean git";
    while [[ -n $1 ]]; do
        case $1 in 
            "b" | "br" | "bra" | "bran" | "branc" | "branch" | "branche" | "branches")
                wizard_clean_git_branches "${@:2}";
                exit $?
            ;;
            __list)
                echo branches
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_clean_git_branches () 
{ 
    common::optional-help "$1" "

  select branches to delete with 'git branch -D'
  ";
    git branch --verbose | common::multi-menu | cut -c 3- | awk '{ print $1 }' | common::map common::do git branch -D
}
wizard_clean_haskell () 
{ 
    common::optional-help "$1" "

  remove intermediary GHC compilation files, *.hi *.o
  ";
    common::do rm ./*.hi ./*.o
}
wizard_configure () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  haskell ...
  keyboard ...
  passwordless-sudo
  tmux ...
  wiki" __name="wizard configure";
    while [[ -n $1 ]]; do
        case $1 in 
            "h" | "ha" | "has" | "hask" | "haske" | "haskel" | "haskell")
                wizard_configure_haskell "${@:2}";
                exit $?
            ;;
            "k" | "ke" | "key" | "keyb" | "keybo" | "keyboa" | "keyboar" | "keyboard")
                wizard_configure_keyboard "${@:2}";
                exit $?
            ;;
            "p" | "pa" | "pas" | "pass" | "passw" | "passwo" | "passwor" | "password" | "passwordl" | "passwordle" | "passwordles" | "passwordless" | "passwordless-" | "passwordless-s" | "passwordless-su" | "passwordless-sud" | "passwordless-sudo" | "ps")
                wizard_configure_passwordless-sudo "${@:2}";
                exit $?
            ;;
            "t" | "tm" | "tmu" | "tmux")
                wizard_configure_tmux "${@:2}";
                exit $?
            ;;
            "w" | "wi" | "wik" | "wiki")
                wizard_configure_wiki "${@:2}";
                exit $?
            ;;
            __list)
                echo haskell keyboard passwordless-sudo tmux wiki
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_configure_haskell () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  stack-links
  vim-depends" __name="wizard configure haskell";
    while [[ -n $1 ]]; do
        case $1 in 
            "s" | "st" | "sta" | "stac" | "stack" | "stack-" | "stack-l" | "stack-li" | "stack-lin" | "stack-link" | "stack-links" | "sl")
                wizard_configure_haskell_stack-links "${@:2}";
                exit $?
            ;;
            "v" | "vi" | "vim" | "vim-" | "vim-d" | "vim-de" | "vim-dep" | "vim-depe" | "vim-depen" | "vim-depend" | "vim-depends" | "vd")
                wizard_configure_haskell_vim-depends "${@:2}";
                exit $?
            ;;
            __list)
                echo stack-links vim-depends
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_configure_haskell_stack-links () 
{ 
    common::optional-help "$1" "

  create 'ghc' and 'ghci' scripts that link to the stack equivalents
  ";
    mkdir -p ~/.local/bin/;
    cat <<EOF > ~/.local/bin/ghc
#!/bin/sh

stack ghc -- "\$@"
EOF

    cat <<EOF > ~/.local/bin/ghci
#!/bin/sh

stack ghci -- "\$@"
EOF

    chmod +x ~/.local/bin/ghc;
    chmod +x ~/.local/bin/ghci
}
wizard_configure_haskell_vim-depends () 
{ 
    common::optional-help "$1" "

  install Vim related Haskell dependencies
  ";
    common::require -f stack;
    common::do stack install hlint apply-refact stylish-haskell
}
wizard_configure_keyboard () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  swap-caps-escape" __name="wizard configure keyboard";
    while [[ -n $1 ]]; do
        case $1 in 
            "s" | "sw" | "swa" | "swap" | "swap-" | "swap-c" | "swap-ca" | "swap-cap" | "swap-caps" | "swap-caps-" | "swap-caps-e" | "swap-caps-es" | "swap-caps-esc" | "swap-caps-esca" | "swap-caps-escap" | "swap-caps-escape" | "sce")
                wizard_configure_keyboard_swap-caps-escape "${@:2}";
                exit $?
            ;;
            __list)
                echo swap-caps-escape
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_configure_keyboard_swap-caps-escape () 
{ 
    common::optional-help "$1" "

  swap caps and escape, doesn't make sense on a Chromebook
  ";
    common::require -f setxkbmap;
    common::do setxkbmap -option caps:swapescape
}
wizard_configure_passwordless-sudo () 
{ 
    common::echo "Add this to /etc/sudoers";
    echo "$(whoami) ALL=(ALL) NOPASSWD:ALL"
}
wizard_configure_tmux () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  layout ..." __name="wizard configure tmux";
    while [[ -n $1 ]]; do
        case $1 in 
            "l" | "la" | "lay" | "layo" | "layou" | "layout")
                wizard_configure_tmux_layout "${@:2}";
                exit $?
            ;;
            __list)
                echo layout
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_configure_tmux_layout () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  horizontal
  tiled
  vertical" __name="wizard configure tmux layout";
    while [[ -n $1 ]]; do
        case $1 in 
            "h" | "ho" | "hor" | "hori" | "horiz" | "horizo" | "horizon" | "horizont" | "horizonta" | "horizontal")
                wizard_configure_tmux_layout_horizontal "${@:2}";
                exit $?
            ;;
            "t" | "ti" | "til" | "tile" | "tiled")
                wizard_configure_tmux_layout_tiled "${@:2}";
                exit $?
            ;;
            "v" | "ve" | "ver" | "vert" | "verti" | "vertic" | "vertica" | "vertical")
                wizard_configure_tmux_layout_vertical "${@:2}";
                exit $?
            ;;
            __list)
                echo horizontal tiled vertical
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_configure_tmux_layout_horizontal () 
{ 
    tmux select-layout even-horizontal
}
wizard_configure_tmux_layout_tiled () 
{ 
    tmux select-layout tiled
}
wizard_configure_tmux_layout_vertical () 
{ 
    tmux select-layout even-vertical
}
wizard_configure_wiki () 
{ 
    common::optional-help "$1" "

  create database entries for all wiki pages
  ";
    [[ -d ~/wiki ]] || common::error "$HOME/wiki not found";
    while read -r wikipage; do
        path="$( basename "$wikipage" )";
        path="${path//.md}";
        d "$path" wiki = "$wikipage";
    done < <( find -L ~/wiki/ -mindepth 1 -maxdepth 1 -type f )
}
wizard_execute () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  timeless" __name="wizard execute";
    while [[ -n $1 ]]; do
        case $1 in 
            "t" | "ti" | "tim" | "time" | "timel" | "timele" | "timeles" | "timeless")
                wizard_execute_timeless "${@:2}";
                exit $?
            ;;
            __list)
                echo timeless
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_execute_timeless () 
{ 
    common::required-help "$2" "[command...] -- [paths...]

  Execute the command against the paths but preserve the timestamp after the
  command completes, regardless of success
  ";
    local cmd=();
    local paths=();
    local found=0;
    for var in "$@";
    do
        if [[ $var == -- ]]; then
            found=1;
        else
            if (( ! found )); then
                cmd+=("$var");
            else
                paths+=("$var");
            fi;
        fi;
    done;
    (( found )) || common::error;
    "didn't find -- delimiter to separate the command from the paths";
    function execute () 
    { 
        local path="$1";
        local when=0;
        when="$( find "$path" -printf '%Ty%Tm%Td%TH%TM\n' )" || common::error "couldn't fetch timestamp for $path";
        "${cmd[@]}" "$path";
        touch -m -t "$when" "$path" || die "restoring timestamp $when to $path returned $?"
    };
    common::for "${paths[@]}" | common::map execute
}
wizard_git () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  fetch
  report" __name="wizard git";
    while [[ -n $1 ]]; do
        case $1 in 
            "f" | "fe" | "fet" | "fetc" | "fetch")
                wizard_git_fetch "${@:2}";
                exit $?
            ;;
            "r" | "re" | "rep" | "repo" | "repor" | "report")
                wizard_git_report "${@:2}";
                exit $?
            ;;
            __list)
                echo fetch report
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_git_fetch () 
{ 
    common::optional-help "$1" "

  recursively discover git directories under the current working directory,
  fetch all branches
  ";
    common::check-network || common::error "no network connection";
    while read -r directory; do
        ( local dir;
        dir="$(dirname "$directory")";
        cd "$dir" || exit;
        git fetch --quiet --all --recurse-submodules --prune;
        echo "$dir" ) &
    done < <(find . -name .git) | sort;
    wait
}
wizard_git_report () 
{ 
    common::optional-help "$1" "

  recursively discover git directories under the current working directory,
  print out a small human readable report on their status
  ";
    while read -r directory; do
        ( local dir;
        dir="$(dirname "$directory")";
        cd "$dir" || exit;
        local status;
        status="$(git status)";
        grep -q 'Your branch is ahead of' <<< "$status" && echo "$dir has local commits not pushed to remote";
        grep -q 'can be fast-forwarded' <<< "$status" && echo "$dir can be fast-forwarded";
        grep -q 'Changes not staged for commit' <<< "$status" && echo "$dir has uncommited, modified files";
        grep -q 'Untracked files' <<< "$status" && echo "$dir has untracked files" ) &
    done < <(find . -name .git) | sort;
    wait
}
wizard_hunt () 
{ 
    common::optional-help "$1" "(-#)

  find processes and send them a signal, default SIGTERM
  can signal multiple processes at once

    wizard hunt
    wizard hunt -9
    wizard hunt vim
    wizard hunt -HUP apache
  ";
    local signal=-TERM;
    case $1 in 
        -*)
            signal="$1";
            shift
        ;;
    esac;
    ps ax | { 
        [[ -n $1 ]] && grep "$1";
        cat
    } | cut -c 1-250 | common::multi-menu | awk '{print $1}' | common::map kill "$signal"
}
wizard_install () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  dot-files
  fish
  fish-dependencies
  git
  java
  lua
  rust
  tmux
  vim
  vnc" __name="wizard install";
    while [[ -n $1 ]]; do
        case $1 in 
            "d" | "do" | "dot" | "dot-" | "dot-f" | "dot-fi" | "dot-fil" | "dot-file" | "dot-files" | "df")
                wizard_install_dot-files "${@:2}";
                exit $?
            ;;
            "f" | "fi" | "fis" | "fish")
                wizard_install_fish "${@:2}";
                exit $?
            ;;
            "f" | "fi" | "fis" | "fish" | "fish-" | "fish-d" | "fish-de" | "fish-dep" | "fish-depe" | "fish-depen" | "fish-depend" | "fish-depende" | "fish-dependen" | "fish-dependenc" | "fish-dependenci" | "fish-dependencie" | "fish-dependencies" | "fd")
                wizard_install_fish-dependencies "${@:2}";
                exit $?
            ;;
            "g" | "gi" | "git")
                wizard_install_git "${@:2}";
                exit $?
            ;;
            "j" | "ja" | "jav" | "java")
                wizard_install_java "${@:2}";
                exit $?
            ;;
            "l" | "lu" | "lua")
                wizard_install_lua "${@:2}";
                exit $?
            ;;
            "r" | "ru" | "rus" | "rust")
                wizard_install_rust "${@:2}";
                exit $?
            ;;
            "t" | "tm" | "tmu" | "tmux")
                wizard_install_tmux "${@:2}";
                exit $?
            ;;
            "v" | "vi" | "vim")
                wizard_install_vim "${@:2}";
                exit $?
            ;;
            "v" | "vn" | "vnc")
                wizard_install_vnc "${@:2}";
                exit $?
            ;;
            __list)
                echo dot-files fish fish-dependencies git java lua rust tmux vim vnc
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_install_dot-files () 
{ 
    common::required-help "$1" "[link | copy]

  link all the configuration files in this repository to their correct
  locations in the system

  if the system doesn't support links (SMB mount), you can use 'copy'
  ";
    common::do mkdir -p "$HOME"/.vim;
    common::do mkdir -p "$HOME"/.config/fish;
    function link () 
    { 
        local here;
        here="$( readlink -f "$1" )";
        local there="${HOME}/$2";
        [[ -n "$here" ]] || common::error "Couldn't find '$1'";
        common::do ln -sf "$here" "$there"
    };
    function copy () 
    { 
        local here;
        here="$( readlink -f "$1" )";
        local there="${HOME}/$2";
        [[ -n "$here" ]] || common::error "Couldn't find '$1'";
        common::do cp -r "$here" "$there"
    };
    case $1 in 
        link | copy)
            op="$1"
        ;;
        *)
            common::error 'options are link or copy'
        ;;
    esac;
    $op etc/config.fish .config/fish/config.fish;
    $op etc/vimrc .vimrc;
    $op etc/tmux.conf .tmux.conf;
    $op etc/bashrc .bashrc;
    $op etc/pylintrc .pylintrc;
    $op lib/fish/functions .config/fish/;
    $op lib/fish/completions .config/fish/;
    $op lib/fish/conf.d .config/fish/
}
wizard_install_fish () 
{ 
    common::optional-help "$1" "

  download and compile fish
  ";
    local version=3.3.1;
    case $( fish --version ) in 
        *3.3.1)
            common::error "fish $version already installed"
        ;;
        *)

        ;;
    esac;
    common::do wget https://github.com/fish-shell/fish-shell/releases/download/$version/fish-$version.tar.xz;
    tar xf fish-$version.tar.xz;
    common::cd fish-$version;
    common::do cmake .;
    common::do make -j;
    common::echo "Run sudo make install"
}
wizard_install_fish-dependencies () 
{ 
    common::program-exists fd || common::do cargo install fd-find;
    common::program-exists bat || common::do cargo install --locked bat;
    common::program-exists fisher || fish -c 'curl -sL https://git.io/fisher | source && fisher install jorgebucaran/fisher';
    common::do fisher install PatrickF1/fzf.fish
}
wizard_install_git () 
{ 
    common::optional-help "$1" "

  install the newest git version
  ";
    common::sudo add-apt-repository ppa:git-core/ppa -y;
    common::sudo apt-get update;
    wizard::apt git
}
wizard_install_java () 
{ 
    common::optional-help "$1" "

  install the Oracle JDK
  ";
    common::sudo add-apt-repository -y ppa:webupd8team/java;
    common::sudo apt update;
    wizard::apt oracle-java8-installer
}
wizard_install_lua () 
{ 
    common::optional-help "$1" "

  install dependencies with apt, compile and install lua 5.3.3
  ";
    common::sudo apt install gcc build-essential libreadline-dev;
    local builddir='lua-5.3.3';
    common::do cd /tmp/;
    [[ -d $builddir ]] || { 
        common::do wget -N 'https://www.lua.org/ftp/lua-5.3.3.tar.gz';
        common::do tar zxvf lua-5.3.3.tar.gz
    };
    common::do cd lua-5.3.3;
    common::do make -j linux;
    common::sudo make install
}
wizard_install_rust () 
{ 
    common::program-exists cargo && common::error "Rust is already installed";
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
}
wizard_install_tmux () 
{ 
    common::optional-help "$1" "

  download, build and install tmux 2.7
  ";
    wizard::apt libevent-dev build-essential libncurses5-dev;
    local builddir='tmux-2.7';
    [[ -d $builddir ]] || { 
        common::do wget 'https://github.com/tmux/tmux/releases/download/2.7/tmux-2.7.tar.gz';
        common::do tar xf tmux-2.7.tar.gz
    };
    common::cd $builddir;
    common::do ./configure;
    common::do make -j;
    common::echo "Run sudo make install"
}
wizard_install_vim () 
{ 
    common::optional-help "$1" "

  compile and install with all feaures enabled
  ";
    wizard::apt git build-essential silversearcher-ag python3-pip;
    [[ -d vim ]] || common::do git clone --depth 1 https://github.com/vim/vim.git;
    common::do cd vim;
    common::do ./configure --with-features=huge --with-lua-prefix=/usr/local --enable-multibyte --enable-rubyinterp=yes --enable-pythoninterp=yes --enable-python3interp=yes --enable-perlinterp=yes --enable-luainterp=yes --enable-gui=auto --enable-cscope --prefix=/usr/local;
    common::do make -j CFLAGS='"-oFast -march=native"'
}
wizard_install_vnc () 
{ 
    common::optional-help "$1" "

  install xfce4 and start a VNC server. for droplets
  ";
    common::sudo apt update;
    wizard::apt xfce4 xfce4-goodies tightvncserver;
    common::sudo vncserver;
    common::sudo vncserver -kill :1;
    cat > "$HOME"/.vnc/xstartup <<EOF
#!/usr/bin/env bash
xrdb \$HOME/.Xresources
startxfce4 &
EOF

    common::do chmod +x "$HOME"/.vnc/xstartup
}
wizard_make () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  ctags ...
  file ...
  hash
  session
  tmpfs
  tmpfs-git-clone" __name="wizard make";
    while [[ -n $1 ]]; do
        case $1 in 
            "c" | "ct" | "cta" | "ctag" | "ctags")
                wizard_make_ctags "${@:2}";
                exit $?
            ;;
            "f" | "fi" | "fil" | "file")
                wizard_make_file "${@:2}";
                exit $?
            ;;
            "h" | "ha" | "has" | "hash")
                wizard_make_hash "${@:2}";
                exit $?
            ;;
            "s" | "se" | "ses" | "sess" | "sessi" | "sessio" | "session")
                wizard_make_session "${@:2}";
                exit $?
            ;;
            "t" | "tm" | "tmp" | "tmpf" | "tmpfs")
                wizard_make_tmpfs "${@:2}";
                exit $?
            ;;
            "t" | "tm" | "tmp" | "tmpf" | "tmpfs" | "tmpfs-" | "tmpfs-g" | "tmpfs-gi" | "tmpfs-git" | "tmpfs-git-" | "tmpfs-git-c" | "tmpfs-git-cl" | "tmpfs-git-clo" | "tmpfs-git-clon" | "tmpfs-git-clone" | "tgc")
                wizard_make_tmpfs-git-clone "${@:2}";
                exit $?
            ;;
            __list)
                echo ctags file hash session tmpfs tmpfs-git-clone
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_make_ctags () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  c
  python" __name="wizard make ctags";
    while [[ -n $1 ]]; do
        case $1 in 
            "c")
                wizard_make_ctags_c "${@:2}";
                exit $?
            ;;
            "p" | "py" | "pyt" | "pyth" | "pytho" | "python")
                wizard_make_ctags_python "${@:2}";
                exit $?
            ;;
            __list)
                echo c python
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_make_ctags_c () 
{ 
    cat <<EOF > /tmp/ctags-ignore.txt
__attribute__
__attribute_deprecated__
__attribute_format_arg__+
__attribute_format_strfmon__+
__attribute_malloc__
__attribute_noinline__
__attribute_pure__
__attribute_used__
__attribute_warn_unused_result__
__attribute_alloc_size__+
__attribute_const__
__attribute_artificial__
__wur
__THROW
__THROWNL
__BEGIN_DECLS
__END_DECLS
__BEGIN_NAMESPACE_STD
__END_NAMESPACE_STD
__USING_NAMESPACE_STD+
__BEGIN_NAMESPACE_C99
__END_NAMESPACE_C99
__USING_NAMESPACE_C99+
__warndecl+
__warnattr+
__errordecl+
__flexarr=[]
__fortify_function
__REDICRECT+
__REDIRECT_NTH+
__REDIRECT_NTHNL+
__ASMNAME+
__ASMNAME2+
__nonnull+
__always_inline
__extern_inline=extern
__extern_always_inline=extern
__extension__
__restrict
__restrict_arr
EOF

    find . -type f \( -name '*.c' -o -name '*.cpp' \) -not -path '*.cquery*' | xargs gcc -M 2> /dev/null | sed -e 's/[\\ ]/\n/g' | sed -e '/^$/d' -e '/\.o:[ \t]*$/d' | sort | uniq | ctags -L - -I /tmp/ctags-ignore.txt --c++-kinds=+p --fields=+iaS --extra=+q
}
wizard_make_ctags_python () 
{ 
    ctags -R --fields=+l --languages=python --python-kinds=-iv
}
wizard_make_file () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  c
  cpp
  java
  python
  shell" __name="wizard make file";
    common::required-help "$1" "[language] [file name]
$__usage
";
    while [[ -n $1 ]]; do
        case $1 in 
            "c")
                wizard_make_file_c "${@:2}";
                exit $?
            ;;
            "c" | "cp" | "cpp")
                wizard_make_file_cpp "${@:2}";
                exit $?
            ;;
            "j" | "ja" | "jav" | "java")
                wizard_make_file_java "${@:2}";
                exit $?
            ;;
            "p" | "py" | "pyt" | "pyth" | "pytho" | "python")
                wizard_make_file_python "${@:2}";
                exit $?
            ;;
            "s" | "sh" | "she" | "shel" | "shell")
                wizard_make_file_shell "${@:2}";
                exit $?
            ;;
            __list)
                echo c cpp java python shell
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_make_file_c () 
{ 
    common::required-help "$1" "[name]

  create a c program out of a template
  ";
    cat > "$1".c <<EOF
#include <stdio.h>

int main(int argc, char ** argv) {

  return 0;
}
EOF

}
wizard_make_file_cpp () 
{ 
    common::required-help "$1" "[name]

  create a cpp program file out of a template
  ";
    cat > "$1".cpp <<EOF
#include <iostream>

int main(int argc, char const *argv[]) {

  return 0;
}
EOF

}
wizard_make_file_java () 
{ 
    common::required-help "$1" "[name]

  create a java program file out of a template
  ";
    cat > "$1".java <<EOF
public class $1 {

  public static void main(String[] argv) {

    System.out.println("Hello world");
  }
}
EOF

}
wizard_make_file_python () 
{ 
    common::required-help "$1" "[name]

  create a pythonscript out of a template
  ";
    cat > "$1.py" <<EOF
#!/usr/bin/env python3

'''
template program
'''

import sys


def main(_):
    ''' list of strings -> none
    '''
    pass


if __name__ == '__main__':
    main(sys.argv)
EOF

}
wizard_make_file_shell () 
{ 
    common::required-help "$1" "[name]

  create a shell script out of a template
  ";
    cat > "$1".sh <<EOF
#!/usr/bin/env bash

EOF

}
wizard_make_hash () 
{ 
    head -c 50 /dev/urandom | md5sum | cut -f 1 -d ' '
}
wizard_make_session () 
{ 
    common::required-help "$1" "[name] (command)

  create a new tmux session and move to it
  ";
    local name="$1";
    local command="$2";
    tmux list-sessions | grep -q "$name" || { 
        if [[ -n $command ]]; then
            tmux new-session -d -s "$name" "$command";
        else
            tmux new-session -d -s "$name";
        fi
    };
    if [[ -n $TMUX ]]; then
        tmux switch-client -t "$name";
    else
        tmux attach-session -t "$name";
    fi;
    _set_context 2> /dev/null
}
wizard_make_tmpfs () 
{ 
    common::required-help "$1" "[target directory]

  create a tmpfs in the target directory. this doesn't overwrite the target
  directory if it exists; it will be available again after you unmount the
  tmpfs

    wizard make tmpfs /usr/local/tmp/tmpfs
    wizard make tmpfs ~/.stack
  ";
    local -r target="$1";
    local -r uid="$(id -u)";
    local -r gid="$(id -g)";
    function unique-name () 
    { 
        echo -n tmpfs_;
        wizard_make_hash '' | head -c 20
    };
    common::do mkdir -p "$target";
    CONFIRM=1 common::sudo mount -t tmpfs -o size=12G,nr_inodes=0,mode=700,uid="$uid",gid="$gid" "$( unique-name )" "$target"
}
wizard_make_tmpfs-git-clone () 
{ 
    common::required-help "$1" "[name] (git repo)

  clone a repo into a new tmpfs directory.

  useful for cloning, make, install, delete work flows

    w make tmpfs-git-clone haskell
    w make tmpfs-git-clone https://github.com/danilop/yas3fs.git
  ";
    function is_repo () 
    { 
        [[ $1 =~ github ]]
    };
    function name-from-repo () 
    { 
        local array=(${1//\// });
        local name="${array[ $(( ${#array[@]} - 1)) ]}";
        result="${name%.*}"
    };
    if is_repo "$1"; then
        name-from-repo "$1";
        local name="$result";
        local repo="$1";
    else
        local name="$1";
        local repo="https://github.com/Gandalf-/$name.git";
    fi;
    wizard_make_tmpfs "$name";
    common::do git clone --depth 1 "$repo" "$name"
}
wizard_media () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  artwork ...
  blog ...
  diving ...
  photos ...
  public ...
  sensors ..." __name="wizard media";
    while [[ -n $1 ]]; do
        case $1 in 
            "a" | "ar" | "art" | "artw" | "artwo" | "artwor" | "artwork")
                wizard_media_artwork "${@:2}";
                exit $?
            ;;
            "b" | "bl" | "blo" | "blog")
                wizard_media_blog "${@:2}";
                exit $?
            ;;
            "d" | "di" | "div" | "divi" | "divin" | "diving")
                wizard_media_diving "${@:2}";
                exit $?
            ;;
            "p" | "ph" | "pho" | "phot" | "photo" | "photos")
                wizard_media_photos "${@:2}";
                exit $?
            ;;
            "p" | "pu" | "pub" | "publ" | "publi" | "public")
                wizard_media_public "${@:2}";
                exit $?
            ;;
            "s" | "se" | "sen" | "sens" | "senso" | "sensor" | "sensors")
                wizard_media_sensors "${@:2}";
                exit $?
            ;;
            __list)
                echo artwork blog diving photos public sensors
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_artwork () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  create
  upload" __name="wizard media artwork";
    while [[ -n $1 ]]; do
        case $1 in 
            "c" | "cr" | "cre" | "crea" | "creat" | "create")
                wizard_media_artwork_create "${@:2}";
                exit $?
            ;;
            "u" | "up" | "upl" | "uplo" | "uploa" | "upload")
                wizard_media_artwork_upload "${@:2}";
                exit $?
            ;;
            __list)
                echo create upload
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_artwork_create () 
{ 
    media::create artwork Artwork
}
wizard_media_artwork_upload () 
{ 
    media::sync artwork
}
wizard_media_blog () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  create
  dependencies
  upload" __name="wizard media blog";
    while [[ -n $1 ]]; do
        case $1 in 
            "c" | "cr" | "cre" | "crea" | "creat" | "create")
                wizard_media_blog_create "${@:2}";
                exit $?
            ;;
            "d" | "de" | "dep" | "depe" | "depen" | "depend" | "depende" | "dependen" | "dependenc" | "dependenci" | "dependencie" | "dependencies")
                wizard_media_blog_dependencies "${@:2}";
                exit $?
            ;;
            "u" | "up" | "upl" | "uplo" | "uploa" | "upload")
                wizard_media_blog_upload "${@:2}";
                exit $?
            ;;
            __list)
                echo create dependencies upload
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_blog_create () 
{ 
    common::file-exists pelicanconf.py || common::error "Not in directory with source content";
    local tmp=/dev/shm/www/;
    common::do mkdir -p "$tmp";
    common::do pelican --ignore-cache -o "$tmp" -t alchemy
}
wizard_media_blog_dependencies () 
{ 
    common::do python3 -m pip install --user --upgrade markdown pelican s3cmd
}
wizard_media_blog_upload () 
{ 
    common::file-exists robots.txt || common::error "Not in directory with html output";
    common::do s3cmd sync -c ~/.s3cfg-sfo --no-mime-magic --guess-mime-type --delete-removed --recursive --acl-public "$(pwd)"/* s3://mirror/web/blog/
}
wizard_media_diving () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  create
  purge ...
  upload" __name="wizard media diving";
    while [[ -n $1 ]]; do
        case $1 in 
            "c" | "cr" | "cre" | "crea" | "creat" | "create")
                wizard_media_diving_create "${@:2}";
                exit $?
            ;;
            "p" | "pu" | "pur" | "purg" | "purge")
                wizard_media_diving_purge "${@:2}";
                exit $?
            ;;
            "u" | "up" | "upl" | "uplo" | "uploa" | "upload")
                wizard_media_diving_upload "${@:2}";
                exit $?
            ;;
            __list)
                echo create purge upload
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_diving_create () 
{ 
    common::optional-help "$1" "

  generate the html and thumbnails for diving.anardil.net.
  ";
    common::program-exists -f 'convert';
    if common::dir-exists /mnt/zfs/Media/; then
        base=/mnt/zfs/Media;
    else
        if common::dir-exists "$HOME"/media/; then
            base="$HOME"/media;
        else
            common::error "Can't find media directory";
        fi;
    fi;
    common::cd ~/working/object-publish/diving-web;
    common::do bash ~/google_drive/code/shell/diving/runner.sh "$base"/Pictures/Diving/;
    common::do python3 ~/google_drive/code/shell/diving/gallery.py "$base"/Pictures/Diving/
}
wizard_media_diving_purge () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  all
  cloudflare
  nginx" __name="wizard media diving purge";
    while [[ -n $1 ]]; do
        case $1 in 
            "a" | "al" | "all")
                wizard_media_diving_purge_all "${@:2}";
                exit $?
            ;;
            "c" | "cl" | "clo" | "clou" | "cloud" | "cloudf" | "cloudfl" | "cloudfla" | "cloudflar" | "cloudflare")
                wizard_media_diving_purge_cloudflare "${@:2}";
                exit $?
            ;;
            "n" | "ng" | "ngi" | "ngin" | "nginx")
                wizard_media_diving_purge_nginx "${@:2}";
                exit $?
            ;;
            __list)
                echo all cloudflare nginx
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_diving_purge_all () 
{ 
    common::optional-help "$1" "

  purge everything in order
  ";
    wizard_media_diving_purge_digital-ocean '';
    common::sleep 60;
    wizard_media_diving_purge_cloudflare '';
    common::sleep 30;
    wizard_media_diving_purge_nginx ''
}
wizard_media_diving_purge_cloudflare () 
{ 
    common::optional-help "$1" "

  purge the CDN for cloudflare
  ";
    common::echo "purging cloudflare cache";
    cloudflare::purge
}
wizard_media_diving_purge_nginx () 
{ 
    common::optional-help "$1" "

  purge the caches for nginx
  ";
    ssh walnut docker exec diving /bin/sh -c 'rm -rf /tmp/example-cache/*'
}
wizard_media_diving_upload () 
{ 
    media::sync diving
}
wizard_media_photos () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  create
  upload" __name="wizard media photos";
    while [[ -n $1 ]]; do
        case $1 in 
            "c" | "cr" | "cre" | "crea" | "creat" | "create")
                wizard_media_photos_create "${@:2}";
                exit $?
            ;;
            "u" | "up" | "upl" | "uplo" | "uploa" | "upload")
                wizard_media_photos_upload "${@:2}";
                exit $?
            ;;
            __list)
                echo create upload
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_photos_create () 
{ 
    media::create photos Photography
}
wizard_media_photos_upload () 
{ 
    media::sync photos
}
wizard_media_public () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  create
  upload ..." __name="wizard media public";
    while [[ -n $1 ]]; do
        case $1 in 
            "c" | "cr" | "cre" | "crea" | "creat" | "create")
                wizard_media_public_create "${@:2}";
                exit $?
            ;;
            "u" | "up" | "upl" | "uplo" | "uploa" | "upload")
                wizard_media_public_upload "${@:2}";
                exit $?
            ;;
            __list)
                echo create upload
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_public_create () 
{ 
    common::optional-help "$1" "

  this calls indexer, which produces the html and thumbnails for
  public.anardil.net.
  ";
    common::program-exists -f 'indexer';
    common::cd ~/google_drive/share/;
    indexer ~/google_drive/code/haskell/indexer/thumbnail.py || exit 0
}
wizard_media_public_upload () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  .indexes
  .thumbnails
  all
  code
  dist
  media
  research
  theme
  timelapse
  zb3" __name="wizard media public upload";
    while [[ -n $1 ]]; do
        case $1 in 
            "." | ".i" | ".in" | ".ind" | ".inde" | ".index" | ".indexe" | ".indexes")
                wizard_media_public_upload_.indexes "${@:2}";
                exit $?
            ;;
            "." | ".t" | ".th" | ".thu" | ".thum" | ".thumb" | ".thumbn" | ".thumbna" | ".thumbnai" | ".thumbnail" | ".thumbnails")
                wizard_media_public_upload_.thumbnails "${@:2}";
                exit $?
            ;;
            "a" | "al" | "all")
                wizard_media_public_upload_all "${@:2}";
                exit $?
            ;;
            "c" | "co" | "cod" | "code")
                wizard_media_public_upload_code "${@:2}";
                exit $?
            ;;
            "d" | "di" | "dis" | "dist")
                wizard_media_public_upload_dist "${@:2}";
                exit $?
            ;;
            "m" | "me" | "med" | "medi" | "media")
                wizard_media_public_upload_media "${@:2}";
                exit $?
            ;;
            "r" | "re" | "res" | "rese" | "resea" | "resear" | "researc" | "research")
                wizard_media_public_upload_research "${@:2}";
                exit $?
            ;;
            "t" | "th" | "the" | "them" | "theme")
                wizard_media_public_upload_theme "${@:2}";
                exit $?
            ;;
            "t" | "ti" | "tim" | "time" | "timel" | "timela" | "timelap" | "timelaps" | "timelapse")
                wizard_media_public_upload_timelapse "${@:2}";
                exit $?
            ;;
            "z" | "zb" | "zb3")
                wizard_media_public_upload_zb3 "${@:2}";
                exit $?
            ;;
            __list)
                echo .indexes .thumbnails all code dist media research theme timelapse zb3
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_public_upload_.indexes () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize .indexes to public.anardil.net
  ";
    local config="$HOME"/.s3cfg-sfo;
    wizard::upload ~/google_drive/share/.indexes
}
wizard_media_public_upload_.thumbnails () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize .thumbnails to public.anardil.net
  ";
    local config="$HOME"/.s3cfg-sfo;
    wizard::upload ~/google_drive/share/.thumbnails
}
wizard_media_public_upload_all () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize state between public.anardil.net and ~/google_drive/share.

  default config is ~/.s3cfg-sfo
  ";
    common::program-exists -f 's3cmd';
    local config="$HOME"/.s3cfg-sfo;
    [[ -n $1 ]] && config="$1";
    function upload () 
    { 
        common::do s3cmd sync -c "$config" --no-mime-magic --guess-mime-type --delete-removed --follow-symlinks --recursive --exclude-from ~/working/config/s3cmd-exclude --acl-public "$1" s3://anardil-public/share/
    };
    upload ~/google_drive/share/.indexes & upload ~/google_drive/share/.thumbnails & for folder in ~/google_drive/share/*;
    do
        common::dir-exists "$folder" || { 
            echo "ignoring $folder";
            continue
        };
        upload "$folder" &
    done;
    wait
}
wizard_media_public_upload_code () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize code to public.anardil.net
  ";
    local config="$HOME"/.s3cfg-sfo;
    wizard::upload ~/google_drive/share/code
}
wizard_media_public_upload_dist () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize dist to public.anardil.net
  ";
    local config="$HOME"/.s3cfg-sfo;
    wizard::upload ~/google_drive/share/dist
}
wizard_media_public_upload_media () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize media to public.anardil.net
  ";
    local config="$HOME"/.s3cfg-sfo;
    wizard::upload ~/google_drive/share/media
}
wizard_media_public_upload_research () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize research to public.anardil.net
  ";
    local config="$HOME"/.s3cfg-sfo;
    wizard::upload ~/google_drive/share/research
}
wizard_media_public_upload_theme () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize theme to public.anardil.net
  ";
    local config="$HOME"/.s3cfg-sfo;
    wizard::upload ~/google_drive/share/theme
}
wizard_media_public_upload_timelapse () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize timelapse to public.anardil.net
  ";
    local config="$HOME"/.s3cfg-sfo;
    wizard::upload ~/google_drive/share/timelapse
}
wizard_media_public_upload_zb3 () 
{ 
    common::optional-help "$1" "[s3cmd config]

  synchronize zb3 to public.anardil.net
  ";
    local config="$HOME"/.s3cfg-sfo;
    wizard::upload ~/google_drive/share/zb3
}
wizard_media_sensors () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  create ..." __name="wizard media sensors";
    while [[ -n $1 ]]; do
        case $1 in 
            "c" | "cr" | "cre" | "crea" | "creat" | "create")
                wizard_media_sensors_create "${@:2}";
                exit $?
            ;;
            __list)
                echo create
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_sensors_create () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  basic
  extremes" __name="wizard media sensors create";
    while [[ -n $1 ]]; do
        case $1 in 
            "b" | "ba" | "bas" | "basi" | "basic")
                wizard_media_sensors_create_basic "${@:2}";
                exit $?
            ;;
            "e" | "ex" | "ext" | "extr" | "extre" | "extrem" | "extreme" | "extremes")
                wizard_media_sensors_create_extremes "${@:2}";
                exit $?
            ;;
            __list)
                echo basic extremes
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_media_sensors_create_basic () 
{ 
    common::optional-help "$1" "

  create the html charts for all sensor data.
  ";
    common::do MPLBACKEND=Agg python3 ~/google_drive/code/python/sensors/sensors.py
}
wizard_media_sensors_create_extremes () 
{ 
    common::optional-help "$1" "

  create the html charts for weekly extremes
  ";
    common::do MPLBACKEND=Agg python3 ~/google_drive/code/python/sensors/sensor-extremes.py ~/google_drive/share/sensors/extremes/
}
wizard_parse () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  json
  xml" __name="wizard parse";
    while [[ -n $1 ]]; do
        case $1 in 
            "j" | "js" | "jso" | "json")
                wizard_parse_json "${@:2}";
                exit $?
            ;;
            "x" | "xm" | "xml")
                wizard_parse_xml "${@:2}";
                exit $?
            ;;
            __list)
                echo json xml
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_parse_json () 
{ 
    common::optional-help "$1" "

  pipe in json and pretty print it

    $ curl remote.com/file.json | w parse json
  ";
    python -m json.tool
}
wizard_parse_xml () 
{ 
    common::required-help "$1" "< file.xml

  pipe in a file an pretty print XML
  ";
    xmllint --format -
}
wizard_regenerate () 
{ 
    common::optional-help "$1" "

  regenerate wizard using auto_wizard, without clobbering ourselves
  ";
    ( sleep 0.5;
    auto_wizard | grep -v 'scripity' ) & disown;
    exit 0
}
wizard_show () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  file-system ...
  frequencies
  haskell ...
  history
  largest-packages
  next-break
  progress
  ratio
  weather" __name="wizard show";
    while [[ -n $1 ]]; do
        case $1 in 
            "f" | "fi" | "fil" | "file" | "file-" | "file-s" | "file-sy" | "file-sys" | "file-syst" | "file-syste" | "file-system" | "fs")
                wizard_show_file-system "${@:2}";
                exit $?
            ;;
            "f" | "fr" | "fre" | "freq" | "frequ" | "freque" | "frequen" | "frequenc" | "frequenci" | "frequencie" | "frequencies")
                wizard_show_frequencies "${@:2}";
                exit $?
            ;;
            "h" | "ha" | "has" | "hask" | "haske" | "haskel" | "haskell")
                wizard_show_haskell "${@:2}";
                exit $?
            ;;
            "h" | "hi" | "his" | "hist" | "histo" | "histor" | "history")
                wizard_show_history "${@:2}";
                exit $?
            ;;
            "l" | "la" | "lar" | "larg" | "large" | "larges" | "largest" | "largest-" | "largest-p" | "largest-pa" | "largest-pac" | "largest-pack" | "largest-packa" | "largest-packag" | "largest-package" | "largest-packages" | "lp")
                wizard_show_largest-packages "${@:2}";
                exit $?
            ;;
            "n" | "ne" | "nex" | "next" | "next-" | "next-b" | "next-br" | "next-bre" | "next-brea" | "next-break" | "nb")
                wizard_show_next-break "${@:2}";
                exit $?
            ;;
            "p" | "pr" | "pro" | "prog" | "progr" | "progre" | "progres" | "progress")
                wizard_show_progress "${@:2}";
                exit $?
            ;;
            "r" | "ra" | "rat" | "rati" | "ratio")
                wizard_show_ratio "${@:2}";
                exit $?
            ;;
            "w" | "we" | "wea" | "weat" | "weath" | "weathe" | "weather")
                wizard_show_weather "${@:2}";
                exit $?
            ;;
            __list)
                echo file-system frequencies haskell history largest-packages next-break progress ratio weather
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_show_file-system () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  directory ...
  files-per-directory" __name="wizard show file-system";
    while [[ -n $1 ]]; do
        case $1 in 
            "d" | "di" | "dir" | "dire" | "direc" | "direct" | "directo" | "director" | "directory")
                wizard_show_file-system_directory "${@:2}";
                exit $?
            ;;
            "f" | "fi" | "fil" | "file" | "files" | "files-" | "files-p" | "files-pe" | "files-per" | "files-per-" | "files-per-d" | "files-per-di" | "files-per-dir" | "files-per-dire" | "files-per-direc" | "files-per-direct" | "files-per-directo" | "files-per-director" | "files-per-directory" | "fpd")
                wizard_show_file-system_files-per-directory "${@:2}";
                exit $?
            ;;
            __list)
                echo directory files-per-directory
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_show_file-system_directory () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  depth
  hash" __name="wizard show file-system directory";
    while [[ -n $1 ]]; do
        case $1 in 
            "d" | "de" | "dep" | "dept" | "depth")
                wizard_show_file-system_directory_depth "${@:2}";
                exit $?
            ;;
            "h" | "ha" | "has" | "hash")
                wizard_show_file-system_directory_hash "${@:2}";
                exit $?
            ;;
            __list)
                echo depth hash
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_show_file-system_directory_depth () 
{ 
    common::required-help "$1" "

  show distribution of directory depth below the current working directory
  ";
    find "$@" -type d | tr -c -d '\n/' | sort | uniq -c
}
wizard_show_file-system_directory_hash () 
{ 
    common::required-help "$1" "

  create a composite hash from everything in a directory
  ";
    local dir="$1";
    if common::program-exists sha1sum; then
        hasher=sha1sum;
    else
        if common::program-exists sha1; then
            hasher=sha1;
        else
            common::error "no hashing program found!";
        fi;
    fi;
    find "$dir" -exec "$hasher" {} + 2> /dev/null | sha1sum | awk '{print $1}'
}
wizard_show_file-system_files-per-directory () 
{ 
    common::required-help "$1" "

  show distribution of number of files in directories below the curent working directory
  ";
    find "$@" -type f | perl -pe 's/\/[^\/]+$/\n/' | sort | uniq -c | awk '{print $1}' | sort -n | { 
        echo instances files-in-dir;
        uniq -c
    } | column -t
}
wizard_show_frequencies () 
{ 
    common::required-help "$1" "[amount]

  count the occurances of each input line
  ";
    sort | uniq -c | sort -nr | head -n "$1"
}
wizard_show_haskell () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  documentation" __name="wizard show haskell";
    while [[ -n $1 ]]; do
        case $1 in 
            "d" | "do" | "doc" | "docu" | "docum" | "docume" | "documen" | "document" | "documenta" | "documentat" | "documentati" | "documentatio" | "documentation")
                wizard_show_haskell_documentation "${@:2}";
                exit $?
            ;;
            __list)
                echo documentation
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_show_haskell_documentation () 
{ 
    common::optional-help "$1" "

  start a Python http.server in the Haskell documentation directory
  ";
    common::require -f stack python3;
    common::cd ~/.stack/programs/x86_64-linux/;
    local latest;
    latest="$(
    find . -maxdepth 1 -type d | tail -n 1
  )";
    latest="${latest//.\/}";
    [[ -n $latest ]] || common::error "Couldn't find any documentation";
    common::cd "$latest"/share/doc/"$latest"/html;
    common::echo "http://localhost:8000";
    common::do python3 -m http.server
}
wizard_show_history () 
{ 
    common::optional-help "$1" "(amount) (range)

  show the <amount> of the most frequently run commands
  ";
    local amount=${1:-25};
    local range=${2:-1};
    fish -c history | cut -f "$range" -d' ' | sort | uniq -c | sort -nr | head -n "$amount"
}
wizard_show_largest-packages () 
{ 
    common::optional-help "$1" "

  list all packages installed, sorted by size

    $ w s lp | head -n 50
  ";
    dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -nr
}
wizard_show_next-break () 
{ 
    common::optional-help "$1" "[--script | break period]

  calculate the last time you took a break (no commands added to fish history)
  and compare that to the current time. if it was more than 30 minutes ago,
  tells you to take a break

    break_period  -> default 10 minutes
    --script      -> only give output when break is recommended
  ";
    local now;
    now=$(date +%s);
    local history=~/.local/share/fish/fish_history;
    local break_period=$(( 60 * 10 ));
    local work_period=$(( 60 * 30 ));
    local previous="$now";
    local last_break="$now";
    local called_by_script=0;
    case $1 in 
        --script)
            called_by_script=1
        ;;
        '')

        ;;
        *)
            break_period="$1"
        ;;
    esac;
    while read -r time; do
        if (( previous - time > break_period )); then
            last_break="$previous";
            break;
        fi;
        previous="$time";
    done < <(
    grep when: $history       | grep -v cmd:       | sort -r       | awk '{print $2}'
    );
    local time=$(( now - last_break ));
    (( called_by_script )) || echo -n "you've been working for $(( time / 60 )) minutes. ";
    if (( time > work_period )); then
        echo "Take a break!";
    else
        if ! (( called_by_script )); then
            echo "You're doing great!";
        fi;
    fi
}
wizard_show_progress () 
{ 
    common::required-help "$1" "

  run a command repeatedly, clear the screen between runs
  ";
    while :; do
        eval "$@";
        sleep 1;
        clear;
    done
}
wizard_show_ratio () 
{ 
    common::required-help "$1" "[amount]

  count the occurances of each input line, produce ratio data
  ";
    sort | uniq -c | sort -nr | head -n "$1" | awk '{a[$2]=$1;s+=$1}END{for(i in a)printf"%-55s%-15d%6.2f%%\n",i,a[i],a[i]/s*100}' | sort -r -k 2,2 -n
}
wizard_show_weather () 
{ 
    curl http://wttr.in/~"${1:-Seattle}"
}
wizard_start () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  http-server
  watcher" __name="wizard start";
    while [[ -n $1 ]]; do
        case $1 in 
            "h" | "ht" | "htt" | "http" | "http-" | "http-s" | "http-se" | "http-ser" | "http-serv" | "http-serve" | "http-server" | "hs")
                wizard_start_http-server "${@:2}";
                exit $?
            ;;
            "w" | "wa" | "wat" | "watc" | "watch" | "watche" | "watcher")
                wizard_start_watcher "${@:2}";
                exit $?
            ;;
            __list)
                echo http-server watcher
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_start_http-server () 
{ 
    if common::program-exists docker; then
        http::docker "$@";
    else
        python3 -c "
from http.server import SimpleHTTPRequestHandler, test
import argparse

class InlineHandler(SimpleHTTPRequestHandler):

    def end_headers(self):
        mimetype = self.guess_type(self.path)
        is_file = not self.path.endswith('/')
        print(mimetype, is_file)

        # This part adds extra headers for some file types.
        if is_file and mimetype in ['text/plain', 'application/octet-stream']:
            self.send_header('Content-Type', 'text/plain')
            self.send_header('Content-Disposition', 'inline')
        super().end_headers()

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--bind', '-b', default='', metavar='ADDRESS',
                        help='Specify alternate bind address '
                             '[default: all interfaces]')
    parser.add_argument('port', action='store',
                        default=8000, type=int,
                        nargs='?',
                        help='Specify alternate port [default: 8000]')
    args = parser.parse_args()
    test(InlineHandler, port=args.port, bind=args.bind)
" "$@";
    fi
}
wizard_start_watcher () 
{ 
    common::required-help "$2" "[path] [command...]
  ";
    local path="$1";
    local previous_value="";
    while :; do
        value="$( stat -c '%Y' "$path" )";
        if [[ "$value" != "$previous_value" ]]; then
            echo "detected change";
            "${@:2}" || common::error "command failure, breaking";
        fi;
        previous_value="$value";
        sleep 1;
    done
}
wizard_switch () 
{ 
    local selection;
    selection="$(wizard show projects | fzf --cycle)";
    [[ -n $selection ]] || common::error "no selection made";
    wizard make session "$selection"
}
wizard_transcode () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  mov-to-mp4
  movies" __name="wizard transcode";
    while [[ -n $1 ]]; do
        case $1 in 
            "m" | "mo" | "mov" | "mov-" | "mov-t" | "mov-to" | "mov-to-" | "mov-to-m" | "mov-to-mp" | "mov-to-mp4" | "mtm")
                wizard_transcode_mov-to-mp4 "${@:2}";
                exit $?
            ;;
            "m" | "mo" | "mov" | "movi" | "movie" | "movies")
                wizard_transcode_movies "${@:2}";
                exit $?
            ;;
            __list)
                echo mov-to-mp4 movies
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_transcode_mov-to-mp4 () 
{ 
    common::required-help "$1" "(--mute) [input.mov ...]

  convert a .mov to .mp4 that's HTML5 compatible
  ";
    local count=$#;
    case "$1" in 
        -m | --mute)
            mute=-an;
            shift
        ;;
    esac;
    while [[ -n $1 ]]; do
        common::echo "processing $1";
        local input="$1";
        local name="${input%.*}";
        local output="$name.mp4";
        common::file-exists "$output" && { 
            "$output already exists";
            continue
        };
        QUIET=1 common::do ffmpeg -hide_banner -loglevel error -i "'$input'" $mute -c:v libx264 -pix_fmt yuv420p -profile:v baseline -level 3.0 -crf 20 -preset veryslow -vf scale=1280:-2 -c:a aac -strict experimental -movflags +faststart -threads 0 "'$output'";
        QUIET=1 common::do chmod 644 "'$output'";
        shift;
    done;
    return $count
}
wizard_transcode_movies () 
{ 
    common::required-help "$1" "[file.avi ...]

  convert all input files to mp4 using ffmpeg, asks for confirmation before
  deleting the source file
  ";
    local preset=veryslow;
    echo "Processing: $*";
    for file in "$@";
    do
        common::do ffmpeg -hide_banner -i "$file" -c:v libx264 -crf 19 -preset "$preset" -strict -2 -c:a aac -b:a 192k -ac 2 "${file%.*}.mp4" || common::error "failed on \"$file\". Giving up";
        common::echo "Waiting...";
        sleep 5;
        common::do rm -i "$file";
    done
}
wizard_update () 
{ 
    [[ -n $1 ]] || "${FUNCNAME[0]}" --help;
    local __usage="
  apt
  platform
  python" __name="wizard update";
    while [[ -n $1 ]]; do
        case $1 in 
            "a" | "ap" | "apt")
                wizard_update_apt "${@:2}";
                exit $?
            ;;
            "p" | "pl" | "pla" | "plat" | "platf" | "platfo" | "platfor" | "platform")
                wizard_update_platform "${@:2}";
                exit $?
            ;;
            "p" | "py" | "pyt" | "pyth" | "pytho" | "python")
                wizard_update_python "${@:2}";
                exit $?
            ;;
            __list)
                echo apt platform python
            ;;
            *)
                if [[ -n $usage ]]; then
                    echo "$usage";
                    exit 0;
                else
                    printf '\n%s\n%s\n\n' "$__name" "$__usage";
                    exit 0;
                fi
            ;;
        esac;
        shift;
    done
}
wizard_update_apt () 
{ 
    wizard_update_platform "$@"
}
wizard_update_platform () 
{ 
    common::optional-help "$1" "

  update system packages, whatever that means on this system
  ";
    case "$( uname )" in 
        Linux)
            (( QUIET )) && extra="-qq";
            common::sudo apt update "$extra";
            common::sudo apt upgrade -y "$extra";
            common::sudo apt-get autoremove -y "$extra"
        ;;
        FreeBSD)
            common::sudo pkg update;
            common::sudo pkg upgrade
        ;;
        *)
            common::error "Unknown platform $( uname )"
        ;;
    esac
}
wizard_update_python () 
{ 
    common::optional-help "$1" "

  update all python packages installed by pip
  ";
    common::check-network || common::error "no network connection";
    python3 -m pip install --upgrade pip;
    python3 -m pip freeze --user --local | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 python3 -m pip install --user
}

[[ "${BASH_SOURCE[0]}" == "${0}" ]] && wizard "$@"
} || exit

