├── .gitignore ├── LICENSE ├── README.md ├── bin ├── LICENSE ├── events.sh ├── hotreload.sh ├── hotreload_test.sh ├── metadata.sh ├── templates.sh ├── templating.sh ├── templating_test.sh ├── utils.sh └── utils_dev.sh ├── demo ├── shite-demo-01-hotreload-begins-5fps-1024px.gif ├── shite-demo-02-hotreload-content-edits-5fps-1024px.gif ├── shite-demo-03-hotreload-style-edits-5fps-1024px.gif ├── shite-demo-04-hotreload-template-updates-5fps-1024px.gif ├── shite-demo-05-hotreload-rebuild-indices-feeds-5fps-1024px.gif └── shite-demo-06-dont-hotreload-full-site-rebuild-5fps-1024px.gif ├── sample ├── demo-screenshots │ ├── shite-demo-about.png │ ├── shite-demo-index.png │ └── shite-demo-resume.png ├── hello-data.html ├── hello.html ├── hello.md └── hello.org ├── shite.sh └── sources ├── LICENSE ├── index.org ├── now.org ├── posts ├── animate-text-art-javascript │ ├── DarkDrawSheetView.png │ ├── HanukkahOfData2022ArtCopyrightDwimmertxt.png │ ├── HanukkahOfData2022ArtSliceCopyrightDwimmertxt.png │ ├── HanukkahOfData2022DarkDrawDrawingViewCopyrightDwimmer.png │ ├── HanukkahOfData2022DarkDrawSheetViewCopyrightDwimmer.png │ ├── animations.js │ ├── blink.ddw │ ├── glider.ddw │ ├── index.org │ ├── loading.ddw │ └── spinner.ddw ├── bad-matrix │ ├── bad_matrix_demo.webm │ └── index.org ├── clojure-mars-rover │ └── index.org ├── cold-restart-total-outage │ └── index.org ├── dismal-arithmetic-dyalog-apl-clojure │ └── index.org ├── dont-hurry-dont-stop-sad-version │ └── index.org ├── emerging-from-dotemacs-bankruptcy-getting-about │ ├── getting-about.jpg │ └── index.org ├── emerging-from-dotemacs-bankruptcy-ide-experience │ ├── emacs-clojure-ide-lsp-cider-reveal-gui.jpeg │ └── index.org ├── emerging-from-dotemacs-bankruptcy-init-begins │ └── index.org ├── emerging-from-dotemacs-bankruptcy-midway-refactor │ └── index.org ├── emerging-from-dotemacs-bankruptcy-packages │ └── index.org ├── emerging-from-dotemacs-bankruptcy │ └── index.org ├── hello-world │ └── index.org ├── how-to-give-a-conference-talk │ └── index.org ├── how-to-not-die-by-a-thousand-cuts │ └── index.org ├── index.org ├── mycelium-clj │ └── index.org ├── n-ways-to-fizzbuzz-in-clojure │ └── index.org ├── people-culture-values-strategy-technology │ └── index.org ├── reader-app-pandoc-bash │ └── index.org ├── shell-aint-a-bad-place-to-fp-part-0-intro │ └── index.org ├── shell-aint-a-bad-place-to-fp-part-1-doug-mcilroys-pipeline │ └── index.org ├── shell-aint-a-bad-place-to-fp-part-2-functions-as-unix-tools │ └── index.org ├── shite-the-static-sites-from-shell-part-1 │ ├── demo-2 │ │ ├── about.html │ │ ├── index.html │ │ └── resume.html │ ├── demo │ │ └── index.html │ ├── index.org │ ├── morpheus-red-blue-pill.jpg │ ├── plain-static-website-cthulahoops-view-source.png │ ├── plain-static-website-cthulahoops.png │ ├── shite-demo-1.png │ ├── shite-demo-2-about.png │ ├── shite-demo-2-index.png │ └── shite-demo-2-resume.png ├── software-debt │ ├── STELLAReportFinalFinal_Coping_With_Complexity.png │ ├── clojure-codebase-introduction-retention-code.png │ └── index.org ├── software-demos │ └── index.org ├── systems-scale-value │ └── index.org ├── tools-for-thought │ └── index.org ├── what-have-you-been-curious-about │ └── index.org ├── what-makes-functional-programming-systems-functional │ └── index.org ├── which-clojure-codebases-to-read-how-and-why │ └── index.org └── why-and-how-i-use-org-mode │ └── index.org └── static ├── css ├── .gitkeep └── style.css ├── img ├── .gitkeep ├── 220px-Lisplogo.png ├── Feed-icon.svg ├── Lisp_logo.png ├── Lisp_logo.svg ├── favicon.ico └── pages │ └── index │ ├── mugshot.jpg │ └── scaling-stasis-death.png └── js └── .gitkeep /.gitignore: -------------------------------------------------------------------------------- 1 | public 2 | posts_meta.csv 3 | .nrepl-port 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | SPDX-License-Identifier: mit OR cc-by-sa-4.0 2 | 3 | Source code released in shite and shite/bin is licensed under the MIT License. 4 | 5 | Content of my website located under shite/sources is licensed under the 6 | Creative Commons Attribution-ShareAlike 4.0 International License, except 7 | where noted otherwise. 8 | -------------------------------------------------------------------------------- /bin/LICENSE: -------------------------------------------------------------------------------- 1 | SPDX-License-Identifier: mit 2 | 3 | MIT License 4 | 5 | Copyright (c) 2019 Aditya Athalye 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /bin/events.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # ################################################## 4 | # FILE EVENTS 5 | # 6 | # Events are structured as a CSV: 7 | # 8 | # unix_epoch_seconds,event_type,base_dir,sub_dir,url_slug,file_type,content_type 9 | # 10 | # ################################################## 11 | 12 | __shite_events_select_filetypes() { 13 | stdbuf -oL grep -E -e "(org|md|json|csv|html|css|js|jpg|jpeg|png|svg|ico|pdf|webm)$" 14 | } 15 | 16 | __shite_events_detect_changes() { 17 | # Monitor a target directory for file CRUD events and emit a structured 18 | # record for each event of interest. Emit a CSV record of the form: 19 | # 20 | # UNIX_EPOCH_SECONDS,EVENT_TYPE,WATCHED_DIR,FILE_NAME 21 | # 22 | # Downstream, we massage this CSV into shite's canonical CSV record. 23 | local watch_dir 24 | watch_dir="$(realpath -e ${1:-$(pwd)})" 25 | local watch_events=${2} 26 | local indefinite=0 # seconds 27 | local one_time=10 #seconds 28 | local seconds 29 | seconds=$([[ ${SHITE_BUILD} == "full" ]] && printf "%s" "${one_time}" || printf "%s" "${indefinite}") 30 | # WATCH A DIRECTORY 31 | inotifywait -m --timeout ${seconds} -r --exclude '/\.git/|/\.#|/#|.*(swp|swx|\~)$' \ 32 | --timefmt "%s" \ 33 | --format '%T,%:e,%w,%f' \ 34 | $([[ -n ${watch_events} ]] && printf "%s %s" "-e" ${watch_events}) \ 35 | ${watch_dir} | 36 | # INCLUDE FILES 37 | # Alas, inotifywait prohibits use of --exclude _and_ --include filters together. 38 | __shite_events_select_filetypes 39 | } 40 | 41 | __shite_events_gen_csv() { 42 | local base_dir 43 | base_dir="$(realpath -e ${1:?'Fail. Please specify a directory to generate events for.'})" 44 | # Given a raw stream of file events, emit a rich CSV record of event info, 45 | # having fields: 46 | # 47 | # UNIX_EPOCH_SECONDS,EVENT_TYPE,BASE_DIR,SUB_DIR,URL_SLUG,FILE_TYPE,CONTENT_TYPE 48 | # 49 | # We analyse events and enrich them with data that will ease dispatch of 50 | # various actions downstream. For example: 51 | # 52 | # - Split the full watched_dir path into base_dir and url_slug parts 53 | # - Enrich file and content type for fine-grained dispatch of file actions 54 | # - etc. 55 | # 56 | # NOTE: we strip trailing slashes from BASE_DIR, and URL_SLUG paths, so that 57 | # we can join them back with slashes interposed, when needed. 58 | # 59 | # TODO: switch to relying on metadata from page front matter (e.g. define 60 | # content_type directly in each post). Also switch to JSON, and depend on jq. 61 | sed -u -E \ 62 | -e "s;(.*),(${base_dir})\/(sources|public)\/(.*\/?),(.*);\1,\2,\3,\4\5;" \ 63 | -e "s;.*\.(.*)$;\0,\1;" \ 64 | -e "s;.*,sources,index.org,.*;\0,rootindex;"\ 65 | -e '/,rootindex$/{p ; d}' \ 66 | -e "s;.*,sources,[-[:alnum:]_]?+\.(org|md|html),.*;\0,rootpages;"\ 67 | -e "s;.*,sources,posts/index.org,.*;\0,blogindex;"\ 68 | -e 's;.*,static\/.*;\0,static;' \ 69 | -e 's;.*,posts\/[-[:alnum:]_]+\/index\.(org|md|html),.*;\0,blog;' \ 70 | -e '/,static|blog|rootindex|rootpages|blogindex|(^$)$/{p ; d}' \ 71 | -e 's;.*;\0,generic;' 72 | } 73 | 74 | # ################################################## 75 | # EVENT FILTERS 76 | # ################################################## 77 | 78 | __shite_events_dedupe() { 79 | # Some editing actions can cause multiple inotify events of the same type for 80 | # the same file for a single edit action. e.g. Writing an edit via Vim causes 81 | # the sequence CREATE, MODIFIED, MODIFIED. Pulling up the helm minibuffer in 82 | # Emacs causes a whole slew of events that are no-ops for us. 83 | # 84 | # We want to ensure we dispatch a hotreload action only on the "final result" 85 | # of any single action on a file. For us, this would be the last event of any 86 | # contiguous sequence of desirable inotify events on the same file. 87 | 88 | stdbuf -oL awk 'BEGIN { FS = "," } {if(!seen[$0]++ && seen[$1]++) print}' 89 | } 90 | 91 | __shite_events_select_sources() { 92 | stdbuf -oL grep -E -e ".*,sources,.*" 93 | } 94 | 95 | __shite_events_select_public() { 96 | stdbuf -oL grep -E -e ".*,public,.*" 97 | } 98 | 99 | __shite_events_drop_public_noisy_events() { 100 | # to suppress noisy events, like when tags are bulk-updated 101 | stdbuf -oL grep -E -v -e ".*,public,tags/.*,.*" 102 | } 103 | 104 | 105 | # ################################################## 106 | # THE EVENT STREAM 107 | # ################################################## 108 | 109 | shite_events_source() { 110 | # UNIX_EPOCH_SECONDS,EVENT_TYPE,WATCHED_DIR,FILE_NAME 111 | local base_dir=${1:?"Fail. Please specify a directory to generate events for."} 112 | local sub_dir=${2:-"sources"} 113 | local event_name=${3:-'MODIFY'} 114 | find "${base_dir}/${sub_dir}" \ 115 | -depth -type f \ 116 | -printf "%Ts,${event_name},%h/,%f\n" | 117 | __shite_events_select_filetypes | 118 | __shite_events_gen_csv "${base_dir}" 119 | } 120 | 121 | shite_events_stream() { 122 | # Watch all relevant files in the given directory, for the given events. 123 | local watch_dir=${1:?"Fail. Please specify a directory to watch"} 124 | local watched_events=${2:-'create,modify,close_write,moved_to,delete'} 125 | 126 | __shite_events_detect_changes \ 127 | ${watch_dir} ${watched_events} | 128 | # Construct events records as a CSV (consider JSON, if jq isn't too expensive) 129 | __shite_events_gen_csv ${watch_dir} 130 | } 131 | -------------------------------------------------------------------------------- /bin/hotreload.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # ################################################## 4 | # Functions to drive browser hot reload. 5 | # 6 | # USAGE 7 | # 8 | # Source these files and call the shite_hot_build_reload function: 9 | # 10 | # source ./bin/utils.sh 11 | # source ./bin/events.sh 12 | # source ./bin/hotreload.sh 13 | # 14 | # shite_hot_build_reload [WATCH DIR] [BROWSER TAB NAME] \ 15 | # [OPTIONAL BROWSER NAME] \ 16 | # [OPTIONAL BASE URL] 17 | # 18 | # It assumes Mozilla Firefox and file:// based navigation by default. 19 | # 20 | # 21 | # EXAMPLES 22 | # 23 | # shite_hot_build_reload "public" 'A site' 24 | # 25 | # shite_hot_build_reload "public" 'A site' "Google Chrome" 26 | # 27 | # shite_hot_build_reload "public" 'A site' "Google Chrome" "http://localhost:8080" 28 | # 29 | # 30 | # LOGIC 31 | # 32 | # Given a stream of event records, in shite's "canonical" CSV record structure: 33 | # - INTERPRET events and generate commands to feed to a command executor 34 | # - "Content" (html) file changes require special handling 35 | # - "Static" (css,js,img) file changes only ever trigger page reload 36 | # - EXECUTE the incoming commands in a streaming fashion 37 | # 38 | # 39 | # WARNINGS 40 | # 41 | # Beware of stdio buffering. Use stdbuf to control it. 42 | # 43 | # Some tools like grep and awk buffer their output and thus block downstream 44 | # actions. But we want instant reaction time. So those buffers are bad for us. 45 | # 46 | # Luckily stdbuf is a general way to tune buffering behaviour. We can work 47 | # with line-buffered output streaming. e.g.: 48 | # 49 | # stdbuf -oL grep something 50 | # 51 | # c.f https://www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html 52 | # ################################################## 53 | 54 | 55 | # ################################################## 56 | # BROWSER COMMAND INTERPRETER FOR FILE EVENTS 57 | # ################################################## 58 | 59 | __shite_hot_cmd_browser_refresh() { 60 | local window_id=${1:?"Fail. We expect window ID to be set in scope."} 61 | 62 | printf "%s\n" \ 63 | "key --window ${window_id} --clearmodifiers 'F5'" 64 | } 65 | 66 | __shite_hot_cmd_goto_url() { 67 | local window_id=${1} 68 | local url=${2} 69 | 70 | printf "%s\n" \ 71 | "key --window ${window_id} --clearmodifiers 'ctrl+l'" \ 72 | "type --window ${window_id} --clearmodifiers --delay 1 ${url}" \ 73 | "key --window ${window_id} --clearmodifiers 'Return'" 74 | } 75 | 76 | __shite_hot_cmd_public_events() { 77 | # Consume the shite event stream and generate xdotool commands to drive 78 | # browser navigation, based on information like event type, file type, 79 | # and how the public file has changed (updated, deleted, moved etc.). 80 | # 81 | # The browser should react only to changes in the `public` directory, 82 | # so we select only those events. 83 | # 84 | # This interpreter: 85 | # 86 | # - Ignores events for non-public files 87 | # - Generates special commands depending on type of modifications to HTML 88 | # "content" pages 89 | # - Emits a catch-all page reload command for events for non-"content" 90 | # files. i.e. "Reload page" is the only sane thing to do when, say, 91 | # some CSS or JS or image changes. 92 | # 93 | local window_id=${1:?"Fail. We expect a window ID."} 94 | local base_url=${2:?"Fail. We expect a base url."} 95 | local url_status 96 | local prev_url_slug 97 | 98 | # Process events only for relevant `public` files. 99 | __shite_events_select_public | 100 | __shite_events_drop_public_noisy_events | 101 | # Generate commands for browser hot reload / navigate. 102 | while IFS=',' read -r timestamp event_type watch_dir sub_dir url_slug file_type content_type 103 | do 104 | # TODO: Find a cleaner alternative. This stateful logic messes up 105 | # occasionally, especially when I also click about the site manually. 106 | # It's not annoying UX-wise, just annoying that the bug exists. 107 | url_status=$( 108 | if [[ "${url_slug}" == "${prev_url_slug}" ]] 109 | then printf "%s" "SAMEURL" 110 | else printf "%s" "NEWURL" 111 | fi 112 | ) 113 | 114 | case "${event_type}:${file_type}:${url_status}" in 115 | # RELOAD 116 | # - When any content file is modified 117 | # - When any non-current content file is deleted 118 | # (because that may affect the current page) 119 | MODIFY:html:SAMEURL ) ;& # catch vim edits 120 | CLOSE_WRITE:CLOSE:html:SAMEURL ) ;& # catch emacs edits 121 | DELETE:html:NEWURL ) 122 | __shite_hot_cmd_browser_refresh ${window_id} 123 | ;; 124 | # GOTO - NAVIGATE 125 | # - Newly-created content file, or 126 | # - Moved/renamed content file 127 | MODIFY:html:NEWURL ) ;& # vim new file 128 | CLOSE_WRITE:CLOSE:html:NEWURL ) ;& # emacs new file 129 | CREATE:html:* ) ;& 130 | MOVED_TO:html:* ) 131 | __shite_hot_cmd_goto_url \ 132 | ${window_id} \ 133 | "${base_url}/${url_slug}" 134 | ;; 135 | # GOTO - FALLBACK 136 | # - home page when the current content file is deleted 137 | DELETE:html:SAMEURL ) 138 | __shite_hot_cmd_goto_url \ 139 | ${window_id} \ 140 | "${base_url}/index.html" 141 | ;; 142 | # RELOAD page for any action on non-content pages, 143 | # presumably static assets. 144 | * ) 145 | __shite_hot_cmd_browser_refresh ${window_id} 146 | ;; 147 | esac 148 | 149 | # Remember the file for the next cycle 150 | prev_url_slug=${url_slug} 151 | done 152 | } 153 | 154 | 155 | # ################################################## 156 | # COMMAND EXECUTOR 157 | # ################################################## 158 | 159 | __shite_hot_cmd_exec() { 160 | # In debug mode, only show the actions, don't do them. 161 | if [[ ${SHITE_BUILD} == "hot" ]] 162 | then stdbuf -oL grep -v '^$' | __tap_stream | xdotool - 163 | else cat - 164 | fi 165 | } 166 | 167 | shite_hot_browser_reload() { 168 | local browser_window_id=${1:?"Fail. Window ID not set."} 169 | local base_url=${base_url:?"Fail. Base URL not set."} 170 | __shite_hot_cmd_public_events ${browser_window_id} ${base_url} | 171 | __shite_hot_cmd_exec 172 | } 173 | 174 | shite_hot_watch_file_events() { 175 | # Watch all files we care about, across sources (org, md, CSS, JS etc.), and 176 | # public (published HTML, CSS, JS etc.), for events of interest, viz.: 177 | # 'create,modify,close_write,moved_to,delete' 178 | local watch_dir=${1:?"Fail. Please specify a directory to watch"} 179 | local events=${2:-'create,modify,close_write,moved_to,delete'} 180 | shite_events_stream ${watch_dir} ${events} 181 | } 182 | 183 | shite_hot_build() { 184 | local base_url=${1:?"Fail. We expect a base URL like 'file://'"} 185 | 186 | # React to source events and CRUD public files 187 | shite_templating_publish_sources ${base_url} > /dev/null 188 | } 189 | 190 | shite_hot_build_reload() { 191 | # React to various file events, hot-build-and-publish `sources` to `public`, 192 | # and then hot-reload (navigate) the browser. 193 | # 194 | # Browser navigation will work only when the site's tab is currently active. 195 | # Hot build / publish works whether or not the tab is active. 196 | 197 | # Maybe improve with getopts later 198 | local watch_dir=${1:?"Fail. Please specify a directory to watch"} 199 | local browser_name=${2:?"Fail. We expect a browser name like \"Mozilla Firefox\"."} 200 | local base_url=${3:?"Fail. We expect a base URL like 'file://'"} 201 | 202 | # LOOKUP WINDOW ID 203 | local window_id 204 | window_id=$(xdotool search --onlyvisible --name ".*${browser_name}$") 205 | 206 | __log_info "$(printf "%s" "Hotreloadin' your shite now! " \ 207 | "'{" \ 208 | "\"watch_dir\": \"$(realpath ${watch_dir})\", "\ 209 | "\"browser_name\": \"${browser_name}\", " \ 210 | "\"base_url\": \"${base_url}\", " \ 211 | "\"window_id\": \"${window_id}\"" \ 212 | "}'")" 213 | 214 | # RUN PIPELINE 215 | shite_hot_watch_file_events ${watch_dir} | 216 | __shite_events_dedupe | 217 | __tap_stream | 218 | tee >(shite_hot_build ${base_url}) | 219 | # Perform hot-reload actions only against changes to public files 220 | tee >(shite_hot_browser_reload ${window_id} ${base_url}) | 221 | # Trigger rebuilds of metadata indices 222 | tee >(shite_metadata_rebuild_indices) 223 | } 224 | -------------------------------------------------------------------------------- /bin/hotreload_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | __shite_test_actions() { 4 | cp -f public/index.html public/deleteme.html 5 | echo "foo" >> public/deleteme.html 6 | mv public/deleteme.html public/deleteme2.html 7 | rm public/deleteme2.html 8 | } 9 | 10 | __shite_test_events() { 11 | cat < for redirect meta, 45 | # viz. 46 | 47 | while IFS=',' read -r timestamp event_type watch_dir sub_dir url_slug file_type content_type 48 | do 49 | case "${sub_dir}:${url_slug}" in 50 | sources:posts/index.org|public:posts/*/index.html ) 51 | __shite_metadata_make_posts_index_csv ${watch_dir} 52 | ;; 53 | esac 54 | done 55 | } 56 | -------------------------------------------------------------------------------- /bin/templating.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # #################################################################### 4 | # FUNCTIONS TO BUILD OUR SHITE PAGES 5 | # #################################################################### 6 | # 7 | # USAGE: 8 | # 9 | # In a new terminal session or tmux pane (i.e. a clean, throwaway environment): 10 | # 11 | # - cd to the root of this project 12 | # 13 | # - add the templates and templating functions to your shell session 14 | # $ source ./bin/templates.sh 15 | # $ source ./bin/templating.sh 16 | # 17 | # - call individual functions to see what happens. 18 | # 19 | # CONTENT FILES CONVENTIONS AND PROCESSING: 20 | # 21 | # Content matter can be in orgmode, markdown, or plain html formats. 22 | # 23 | # Each page may specify its own metadata. This will be used in addition 24 | # to global (site-wide) metadata, to fill out templates and/or control page 25 | # processing. Page-specific metadata should be written in syntax that is 26 | # standard for that kind of content. 27 | # 28 | # $ declare -A shite_page_data="$(__shite_templating_get_page_front_matter ./sample/hello.html)" 29 | # 30 | # $ cat ./sample/hello.html | shite_templates_common_default_page 31 | # 32 | # #################################################################### 33 | 34 | __shite_templating_get_page_front_matter() { 35 | # Parse "front matter" of content documents and return a stream of 36 | # Key,Value CSV pairs. These can be further processed into shite_page_data 37 | # array or translated to HTML metadata. 38 | # 39 | # We want our parsed keys to always be lowercase and obey snake_case. Values 40 | # can be any case. 41 | # 42 | # NOTE: Metadata syntax. 43 | # 44 | # We expect front matter based metadata definitions to be compatible with 45 | # the given content type. 46 | # 47 | # For html content, we can simply use tags. Whereas, for org and 48 | # markdown, we define metadata between some well-defined /begin,end/ pair 49 | # of markers. Given these markers, we can use sed-based multiline processing 50 | # techniques to parse only the text between the markers. 51 | # cf. https://unix.stackexchange.com/a/78479 52 | # 53 | # NOTE: `sed` flags. 54 | # 55 | # The -n flag is required to prevent pattern space printing. This ensures: 56 | # a) metadata only between the begin/end markers is streamed out, 57 | # b) only properly demarcated values are set in the array, and 58 | # c) we don't accidentally set empty keys, which begets errors: 59 | # `-bash: shite_page_data[${key}]: bad array subscript` 60 | # 61 | # We also use GNU sed extensions `I` to match key tokens regardless of 62 | # case, but we then convert all those to lowercase using '\L'token'\E'. 63 | local file_type=${1:?"Fail. We expect file type of the content."} 64 | case ${file_type} in 65 | org ) 66 | # Multiline processing of org-style header/preamble syntax, boxed 67 | # between begin/end markers we have defined. We use org-mode's own 68 | # comment line syntax to write the begin/end markers. 69 | # cf. https://orgmode.org/guide/Comment-Lines.html 70 | sed -n -E \ 71 | -e '/^\#\s+shite_meta/I,/^\#\s+shite_meta/I{/\#\s+shite_meta.*/Id; s/^\#\+(\w+)\:\s+(.*)/\L\1\E,\2/Ip}' 72 | ;; 73 | md ) 74 | # Multiline processing of Jekyll-style YAML front matter, boxed 75 | # between `---` separators. 76 | sed -n -E \ 77 | -e '/^\-{3,}/,/^\-{3,}/{/^\-{3,}.*/d; s/^(\w+)\:\s+(.*)/\L\1\E,\2/Ip}' 78 | ;; 79 | html ) 80 | # Use HTML meta tags and parse them, according to this convention: 81 | # 82 | # cf. https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML 83 | sed -n -E \ 84 | -e 's;^\s?;\L\1\E,\2;Ip' 85 | ;; 86 | esac 87 | } 88 | 89 | __shite_templating_set_page_data() { 90 | # We always set data afresh, because it must be page-specific. 91 | unset shite_page_data 92 | declare -Agx shite_page_data 93 | 94 | local file_path=${1:?"Fail. We expect full path to the file."} 95 | local file_type=${file_path##*\.} # Remove up to last period, geedily from left 96 | local optional_metadata_csv_file=${2} 97 | 98 | # NOTE: We use input redirection to set values in the *current* environment. 99 | # One may be tempted to pipeline front matter CSV into this function, but 100 | # that causes the data to be set in a subshell, which of course, does not 101 | # mutate the outside environment. 102 | while IFS=',' read -r key val 103 | do shite_page_data[${key}]="${val}" 104 | done < <(cat ${file_path} | 105 | # Lift page-specific frontmatter metatdata 106 | __shite_templating_get_page_front_matter ${file_type} | 107 | # Inject additional page-specific metadata 108 | cat - ${optional_metadata_csv_file} 109 | ) 110 | } 111 | 112 | __shite_templating_compile_source_to_html() { 113 | # If content has front matter metadata, it is presumed to be in a format 114 | # that the content compiler can safely process and elide or ignore. 115 | local file_type=${1:?"Fail. We expect file type of content like html, org, md etc."} 116 | 117 | case ${file_type} in 118 | html ) 119 | cat - 120 | ;; 121 | md ) 122 | pandoc -f markdown -t html 123 | ;; 124 | org ) 125 | pandoc -f org -t html 126 | ;; 127 | esac 128 | } 129 | 130 | __shite_templating_wrap_content_html() { 131 | local content_type=${1:?"Fail. We expect content_type such as blog, index, static, or generic."} 132 | local watch_dir=${2:?"Fail. We expect watch directory."} 133 | local posts_meta_file=${3:-"${watch_dir}/posts_meta.csv"} 134 | 135 | case ${content_type} in 136 | generic ) 137 | cat - 138 | ;; 139 | blog ) 140 | shite_template_posts_article 141 | ;; 142 | rootindex|rootpages ) 143 | cat - 144 | ;; 145 | blogindex ) 146 | shite_template_indices_append_tags_posts ${posts_meta_file} 147 | ;; 148 | * ) 149 | __log_info "__shite_templating_wrap_content_html does not handle the given event." 150 | ;; 151 | esac 152 | } 153 | 154 | __shite_templating_wrap_page_html() { 155 | # Given well-formed body HTML content, punch it into the appropriate 156 | # page template, to emit a complete, well-formed page. 157 | 158 | local content_type=${1:?"Fail. We expect content type."} 159 | 160 | case ${content_type} in 161 | rootindex ) 162 | shite_template_home_page 163 | ;; 164 | rootpages ) 165 | shite_template_common_default_page 166 | ;; 167 | blog|blogindex ) 168 | shite_template_common_default_page 169 | ;; 170 | * ) # let all other HTML content through as-is, e.g. standalone html 171 | # pages nested under a blog post. i.e. 172 | # posts/post-url-slug/microsite-example-under-post/some-page.html 173 | cat - 174 | ;; 175 | esac 176 | } 177 | 178 | # #################################################################### 179 | # BUILD PUBLIC HTML 180 | # 181 | # By convention we write all processed HTML into the "public" folder. 182 | # 183 | # This function references global data, and injects page-specific data 184 | # that it gets from events (e.g. URL info) and/or metadata from page 185 | # front matter. 186 | # #################################################################### 187 | 188 | shite_templating_publish_sources() { 189 | # Analyse events and dispatch appropriate content processing actions. 190 | # e.g. Punch orgmode blog content through its content processor, 191 | # or garbage collect a static file from public (published) targety, if its 192 | # source file is deleted or renamed (moved). 193 | 194 | local base_url=${1:?"Fail. We expect base url."} 195 | 196 | __shite_events_select_sources | 197 | while IFS=',' read -r timestamp event_type watch_dir sub_dir url_slug file_type content_type 198 | do 199 | # Set page-specific data into page context, that we can infer only at 200 | # the time of building the page. The page builder function depends on 201 | # us doing so before calling it. 202 | 203 | # transform content url_slug -to-> html file name 204 | local html_url_slug="${url_slug%\.*}.html" 205 | # transform content url_slug -to-> directory root for the html content 206 | local url_slug_root 207 | url_slug_root="$(dirname ${url_slug})" 208 | 209 | __shite_templating_set_page_data \ 210 | "${watch_dir}/sources/${url_slug}" \ 211 | <(cat <<<"canonical_url,${base_url}/${html_url_slug}") 212 | 213 | case "${event_type}:${file_type}:${content_type}" in 214 | DELETE:*:generic|MOVED_FROM:*:generic ) 215 | # GC the specific resource 216 | rm -f "${watch_dir}/public/${html_url_slug}" 217 | # GC the content's base dir too, IFF it becomes empty 218 | # NOTE: `find` is sensitive to sequence of expressions. RTFM 219 | # to make sure it is used correctly here. 220 | find "$(dirname "${watch_dir}/public/${html_url_slug_root:-'.'}")" \ 221 | -depth -type d -empty -delete 222 | # TODO: Instead of deleting the directory, write an index.html 223 | # as an HTML redirect page. In the , put something like... 224 | # 225 | # And in the body, some message like... 226 | #

Page moved! Redirecting you in 5s. Hurried? Click here.

227 | ;; 228 | *:html:blog|*:org:blog|*:md:blog ) ;& 229 | *:html:generic|*:org:generic|*:md:generic ) ;& 230 | *:html:rootpages|*:org:rootpages|*:md:rootpages ) ;& 231 | *:org:rootindex|*:org:blogindex ) 232 | # Handy trick to modify templates, without having to restart 233 | # our process each time we change template functions. 234 | if [[ ${SHITE_DEBUG_TEMPLATES} == "debug" ]] 235 | then source "$(pwd)/bin/templates.sh" 236 | fi 237 | 238 | # Idempotent. Make the slug's root directory IFF it does not exist. 239 | mkdir -p "${watch_dir}/public/${url_slug_root}" 240 | 241 | # Proc known types of content files, e.g. compile org blog 242 | # to HTML, and write it to the public directory 243 | cat "${watch_dir}/sources/${url_slug}" | 244 | __shite_templating_compile_source_to_html ${file_type} | 245 | __shite_templating_wrap_content_html ${content_type} ${watch_dir} | 246 | __shite_templating_wrap_page_html ${content_type} \ 247 | > "${watch_dir}/public/${html_url_slug}" 248 | 249 | # We want blogindex page updates to also mean "please hot-build 250 | # other site-wide stuff like tags indices, RSS feed etc." 251 | if [[ "${file_type}:${content_type}" == "org:blogindex" ]] 252 | then local posts_meta_file="${watch_dir}/posts_meta.csv" 253 | 254 | # PER TAG index pages of posts, from tab-separated records 255 | # of post metadata 256 | cut -f3 ${posts_meta_file} | 257 | tr ' ' '\n' | grep -v "^$" | sort -u | 258 | while read -r tag_name 259 | do local tag_dir="${watch_dir}/public/tags/${tag_name}" 260 | 261 | mkdir -p "${tag_dir}" 262 | 263 | shite_template_indices_tag_page_index \ 264 | ${tag_name} ${posts_meta_file} | 265 | __shite_templating_wrap_page_html ${content_type} \ 266 | > "${tag_dir}/index.html" 267 | done 268 | 269 | # ALL TAGS root index page of posts 270 | shite_template_indices_tags_root_index ${posts_meta_file} | 271 | __shite_templating_wrap_page_html ${content_type} \ 272 | > "${watch_dir}/public/tags/index.html" 273 | 274 | # FEEDs and SITEMAP etc. 275 | shite_template_rss_feed \ 276 | ${posts_meta_file} \ 277 | > "${watch_dir}/public/${shite_global_data[feed_xml]}" 278 | 279 | shite_template_sitemap \ 280 | ${posts_meta_file} \ 281 | > "${watch_dir}/public/${shite_global_data[sitemap_xml]}" 282 | 283 | shite_template_robots_txt \ 284 | > "${watch_dir}/public/robots.txt" 285 | fi 286 | ;; 287 | DELETE:*:static|MOVED_FROM:*:static ) 288 | # GC dead static files 289 | rm -f "${watch_dir}/public/${url_slug}" 290 | ;; 291 | *:*:generic ) ;& 292 | *:*:static ) 293 | # Idempotent. Make the slug's root directory IFF it does not exist. 294 | mkdir -p "${watch_dir}/public/${url_slug_root}" 295 | 296 | # Overwrite public versions of any modified generic, or static 297 | # files, or create them if they don't exist. 298 | cp -u \ 299 | "${watch_dir}/sources/${url_slug}" \ 300 | "${watch_dir}/public/${url_slug}" 301 | ;; 302 | * ) 303 | __log_info "shite_templating_publish_sources does not handle the given event." 304 | # __log_info "${timestamp},${event_type},${watch_dir},${sub_dir},${url_slug},${file_type},${content_type}" 305 | ;; 306 | esac 307 | done 308 | } 309 | -------------------------------------------------------------------------------- /bin/templating_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source ./templating.sh 4 | 5 | # Test metadata parsing for org, md, html formats. We want our 6 | # parsed keys to always be lowercase. Values can be any case. 7 | 8 | # orgmode metada parsing: 9 | # We rely on standard org buffer header metadata syntax. 10 | cat <<'EOF' | 11 | # SHITE_META 12 | #+TITLE: This is a Title 13 | #+slug: this/is/a/slug 14 | #+DATE: Friday 26 August 2022 03:38:01 PM IST 15 | #+TAGS: foo BAR baz QUXX 16 | # SHITE_META 17 | #+more_org_metadata: but not processed as shite metadata 18 | #+still_more_org_metadata: and still not processed as shite metadata 19 | 20 | * this is a heading 21 | 22 | this is some orgmode content 23 | 24 | #+TOC: headlines 1 local 25 | 26 | ** this is a subheading 27 | - this is a point 28 | - this is another point 29 | - a third point 30 | EOF 31 | __shite_templating_get_page_front_matter org 32 | 33 | 34 | # markdown metada parsing: 35 | # We rely on Jekyll-styl YAML front matter syntax. 36 | cat <<'EOF' | 37 | --- 38 | TITLE: This is a Title 39 | slug: this/is/a/slug 40 | DATE: Friday 26 August 2022 03:38:01 PM IST 41 | TAGS: foo BAR baz QUXX 42 | --- 43 | TAGS: these should not appear in our metadata 44 | date: Friday 26 August 2022 05:32:36 PM 45 | title: This is not a Title 46 | slug: this/is/NOT/a/slug 47 | 48 | # this is a heading 49 | 50 | this is some markdown content 51 | 52 | ## this is a subheading 53 | - this is a point 54 | - this is another point 55 | - a third point 56 | EOF 57 | __shite_templating_get_page_front_matter md 58 | 59 | 60 | # html metadata parsing: 61 | # We rely on standard meta tags with this convention for key/value pair: 62 | # 63 | cat <<'EOF' | 64 | 65 | 66 | 67 | 68 | 69 |

This is a heading

70 |

This is some text

71 |

This is a subheading

72 |

73 |

78 |

79 | EOF 80 | __shite_templating_get_page_front_matter html 81 | -------------------------------------------------------------------------------- /bin/utils.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Utils mostly copied over from my "Bash Toolkit" 4 | # cf. https://github.com/adityaathalye/bash-toolkit 5 | 6 | __to_stderr() { 7 | # Ref: I/O Redirection: http://tldp.org/LDP/abs/html/io-redirection.html 8 | 1>&2 printf "%s %s\n" "$(date --iso-8601=seconds)" "$@" 9 | } 10 | 11 | __log_info() { 12 | __to_stderr "$(printf "%s %s\n" "INFO $0" "$@")" 13 | } 14 | 15 | __tap_stream() { 16 | tee >(1>&2 cat -) 17 | } 18 | 19 | __ensure_deps() { 20 | # Given a list of dependencies, emit unmet dependencies to stderr, 21 | # and return 1. Otherwise silently return 0. 22 | local required_deps="${@}" 23 | local err_code=0 24 | for prog in ${required_deps} 25 | do if ! which ${prog} > /dev/null 26 | then __log_info "PACKAGE NOT FOUND: ${prog}. Things will break." 27 | err_code=1 28 | fi 29 | done 30 | return ${err_code} 31 | } 32 | 33 | __ensure_min_bash_version() { 34 | # Given a 'Major.Minor.Patch' SemVer number, return 1 if the system's 35 | # bash version is older than the given version. Default to 4.0.0. 36 | # Hat tip: https://unix.stackexchange.com/a/285928 37 | local semver="${1:-4.0.0}" 38 | local bashver="${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}.${BASH_VERSINFO[2]}" 39 | 40 | [[ $(printf "%s\n" ${semver} ${bashver} | sort -V | head -1) == "${semver}" ]] 41 | } 42 | 43 | __html_escape() { 44 | # Use to escape HTML when making XML files like RSS feeds or Sitemaps. 45 | # It could be a sed one-liner, but it could also be a very badly behaved 46 | # sed one-liner, causing all manner of breakages and bugs. But we have jq, 47 | # and jq is neat! Thanks to: https://stackoverflow.com/a/71191653 48 | # 49 | # echo "\"'&<>" | jq -Rr @html 50 | # "'&<> 51 | 52 | jq -Rr @html 53 | } 54 | 55 | __url_encode() { 56 | # Use to urlencode data to use in submit links, such as submit to HN. e.g.: 57 | # 58 | # discuss at HN 59 | # 60 | # Thanks to: https://stackoverflow.com/a/34407620/1577057 61 | 62 | jq -sRr @uri 63 | } 64 | -------------------------------------------------------------------------------- /bin/utils_dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # #################################################################### 3 | # SITE PUBLISHING 4 | # 5 | # Convenience functions to remind us how to create the full site, and 6 | # publish it to the public directory. 7 | # 8 | # TODO: Fix this whole namespace. It has fallen to ruin from disuse. 9 | # 10 | # #################################################################### 11 | 12 | __shite_devutil_tidy_check_html() { 13 | find "${base_dir}/public/" -type f -name "*.html" | 14 | __tap_stream | 15 | xargs -0 tidy -q -e 16 | } 17 | 18 | __shite_devutil_trigger_all_sources() { 19 | find "$(pwd)/sources" -type f | 20 | while read -r f 21 | do touch -m ${f} 22 | done 23 | } 24 | 25 | __shite_devutil_minify_all_in_place() { 26 | minify -r -o . . 27 | } 28 | -------------------------------------------------------------------------------- /demo/shite-demo-01-hotreload-begins-5fps-1024px.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/demo/shite-demo-01-hotreload-begins-5fps-1024px.gif -------------------------------------------------------------------------------- /demo/shite-demo-02-hotreload-content-edits-5fps-1024px.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/demo/shite-demo-02-hotreload-content-edits-5fps-1024px.gif -------------------------------------------------------------------------------- /demo/shite-demo-03-hotreload-style-edits-5fps-1024px.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/demo/shite-demo-03-hotreload-style-edits-5fps-1024px.gif -------------------------------------------------------------------------------- /demo/shite-demo-04-hotreload-template-updates-5fps-1024px.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/demo/shite-demo-04-hotreload-template-updates-5fps-1024px.gif -------------------------------------------------------------------------------- /demo/shite-demo-05-hotreload-rebuild-indices-feeds-5fps-1024px.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/demo/shite-demo-05-hotreload-rebuild-indices-feeds-5fps-1024px.gif -------------------------------------------------------------------------------- /demo/shite-demo-06-dont-hotreload-full-site-rebuild-5fps-1024px.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/demo/shite-demo-06-dont-hotreload-full-site-rebuild-5fps-1024px.gif -------------------------------------------------------------------------------- /sample/demo-screenshots/shite-demo-about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sample/demo-screenshots/shite-demo-about.png -------------------------------------------------------------------------------- /sample/demo-screenshots/shite-demo-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sample/demo-screenshots/shite-demo-index.png -------------------------------------------------------------------------------- /sample/demo-screenshots/shite-demo-resume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sample/demo-screenshots/shite-demo-resume.png -------------------------------------------------------------------------------- /sample/hello-data.html: -------------------------------------------------------------------------------- 1 | 2 |

Hello, world!

3 |

How are you doing today?

4 |

I'm here.

5 |

And I'm going to take you head-on...

6 | -------------------------------------------------------------------------------- /sample/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

This is a heading

7 |

This is some text

8 |

This is a subheading

9 |

10 |

15 |

16 | -------------------------------------------------------------------------------- /sample/hello.md: -------------------------------------------------------------------------------- 1 | --- 2 | TITLE: This is a Title 3 | slug: this/is/a/slug 4 | DATE: Friday 26 August 2022 03:38:01 PM IST 5 | TAGS: foo BAR baz QUXX 6 | --- 7 | 8 | # this is a heading 9 | 10 | this is some markdown content 11 | 12 | ## this is a subheading 13 | - this is a point 14 | - this is another point 15 | - a third point 16 | -------------------------------------------------------------------------------- /sample/hello.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+TITLE: This is a Title 3 | #+slug: this/is/a/slug 4 | #+DATE: Friday 26 August 2022 03:38:01 PM IST 5 | #+TAGS: foo BAR baz QUXX 6 | # SHITE_META 7 | #+more_org_metadata: but not processed as shite metadata 8 | #+still_more_org_metadata: and still not processed as shite metadata 9 | 10 | * this is a heading 11 | 12 | this is some orgmode content 13 | 14 | #+TOC: headlines 1 local 15 | 16 | ** this is a subheading 17 | - this is a point 18 | - this is another point 19 | - a third point 20 | -------------------------------------------------------------------------------- /shite.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Do it all in a subshell so we don't pollute the existing teminal session. 4 | ( 5 | # Ensure extglob is set, for enhanced Pattern Matching (see Bash manual). 6 | shopt -s extglob 7 | 8 | # Bring in all the functions. 9 | source ./bin/utils.sh 10 | source ./bin/templates.sh 11 | source ./bin/templating.sh 12 | source ./bin/events.sh 13 | source ./bin/metadata.sh 14 | source ./bin/hotreload.sh 15 | 16 | # Check for various requirements and dependencies 17 | __ensure_min_bash_version "4.4" 18 | # Events and streaming 19 | __ensure_deps "inotifywait" "stdbuf" 20 | # Events and Content Processing 21 | __ensure_deps "gawk" "pandoc" "tidy" "xmllint" 22 | # GUI / Browser actions 23 | __ensure_deps "xdotool" "xdg-open" 24 | 25 | # Cue shite for everyday local editing and publishing 26 | base_dir="$(realpath -e ${1:?'Fail. Source directory must be specified.'})" 27 | SHITE_BUILD=${2:-"hot"} # or "full" 28 | base_url=${3:-"file://${base_dir}/public"} 29 | browser_name=${4:-"Mozilla Firefox"} 30 | SHITE_DEBUG_TEMPLATES="debug" 31 | 32 | # Set globally-relevant information that we inject into components, 33 | # and that we may also use to control site build behaviour. 34 | # TODO: Don't hardcode. Instead, put a canonical index.org in the 35 | # index.org (and/or index.html) at 36 | # the root of `sources`, using our little metadata parser from templating.sh 37 | declare -A shite_global_data=( 38 | [title]="Eval / Apply is pure magic" 39 | [title_icon]="static/img/Lisp_logo.svg" 40 | [title_icon_png]="static/img/Lisp_logo.svg" 41 | [favicon]="static/img/favicon.ico" 42 | [author]="Aditya Athalye" 43 | [description]="Evaling and Applying forever." 44 | [keywords]="systems thinking,functional programming,architecture,software design,technology leadership,devops,clojure" 45 | [base_url]="${base_url}" 46 | [feed_xml]="index.xml" 47 | [sitemap_xml]="sitemap.xml" 48 | ) 49 | 50 | # Oh yeah! 51 | if [[ ${SHITE_BUILD} == "hot" ]] 52 | then # Run hotreload in streaming mode, with a new browser session 53 | ( firefox --new-tab "${base_url}/index.html" & ) 54 | shite_hot_build_reload "${base_dir}" "${browser_name}" "${base_url}" \ 55 | > /dev/null 56 | fi 57 | 58 | if [[ ${SHITE_BUILD} == "full" ]] 59 | then 60 | eventsource="${base_dir}/eventsource.txt" 61 | rm -r "${base_dir}/public" 62 | mkdir -p "${base_dir}/public" 63 | 64 | # Set up watches that stream out events for updated files 65 | shite_hot_watch_file_events "${base_dir}" 'create' | 66 | tee "${base_dir}/eventsource_published.txt" & 67 | 68 | # Generate events to feed into build pipeline 69 | shite_events_source "${base_dir}" "sources" "MODIFY" \ 70 | > "${eventsource}" 71 | 72 | __log_info "About to rebuild content." 73 | stdbuf -oL grep -v -E "rootindex|blogindex$" "${eventsource}" | 74 | shite_hot_build "${base_url}" > /dev/null 75 | __log_info "Content rebuilt." 76 | 77 | __log_info "About to rebuild posts index CSV." 78 | __shite_metadata_make_posts_index_csv ${base_dir} 79 | __log_info "Posts index CSV rebuilt." 80 | 81 | __log_info "About to rebuild index pages." 82 | stdbuf -oL grep -E "rootindex|blogindex$" "${eventsource}" | 83 | shite_hot_build "${base_url}" > /dev/null 84 | __log_info "Index pages rebuilt." 85 | 86 | __log_info "Full rebuild done." 87 | fi 88 | ) 89 | -------------------------------------------------------------------------------- /sources/LICENSE: -------------------------------------------------------------------------------- 1 | SPDX-License-Identifier: cc-by-sa-4.0 2 | 3 | © copyright Aditya Athalye. Except where otherwise noted, content on 4 | this site is licensed under a Creative Commons Attribution-ShareAlike 4.0 5 | International License, the same one used by Wikipedia. 6 | 7 | https://creativecommons.org/licenses/by-sa/4.0/ 8 | -------------------------------------------------------------------------------- /sources/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Hi, I'm Aditya Athalye. 3 | #+subtitle: Sentient Learning Machine & Human General Intelligence. 4 | #+summary: Stuff I like to nerd about. 5 | #+author: Adi 6 | #+tags: index 7 | #+date: 2021-11-10 8 | # SHITE_META 9 | 10 | The dashing duo of */eval/apply/* [fn:1] and */learn generously/* [fn:2] pervade 11 | all that I do [fn:3]. 12 | 13 | I [[./posts/index.html#blog-index-list][blog here]] and write the occasional newsletter [fn:4]. 14 | Pet [[./posts/index.html#tags-index-list][topics]] include systems, complexity, 15 | organisation design, architecture, and functional programming. 16 | 17 | /[[./now.html#main][Now]]/ is a year of total reinvention; body, mind, and work. 18 | And I'm intent on making [[./posts/software-demos/index.html#main][demo software]] for fun (Also money. It's fun to have money.). 19 | 20 | [fn:1] */eval/apply is wicked cool.../* Circa 1960, A.I. pioneer John McCarthy gave us 21 | ~eval~ and ~apply~, two mutually recursive LISP functions that encode 22 | [[https://www.gnu.org/software/mes/manual/html_node/LISP-as-Maxwell_0027s-Equations-of-Software.html][the kernel of all of programming]]. 23 | Like /yin/yang/ ☯, they contain each other. And 24 | they evoke other nonduals to live by; /diffuse/focus/, /abstract/reify/, 25 | /design/develop/. 26 | 27 | #+begin_quote 28 | *Stuart Feldman*: If nothing else, Lisp was carefully defined in terms of Lisp. 29 | 30 | *Alan Kay*: Yes, that was the big revelation to me when I was in graduate 31 | school—when I finally understood that the half page of code on the bottom of 32 | page 13 of the Lisp 1.5 manual was Lisp in itself. These were “Maxwell’s 33 | Equations of Software!” This is the whole world of programming in a few lines 34 | that I can put my hand over. 35 | #+end_quote 36 | 37 | [fn:2] */Learn generously is my favourite [[https://www.recurse.com/self-directives][self-directive]].../* 38 | coined by the gentlepeople at my favourite programmers' community, /*the Recurse Center*/. 39 | One stands on the shoulders of giants. One has received much generosity. One 40 | benefits greatly from contributions to the public commons. One tries to give back 41 | in one's meager ways. 42 | #+begin_export html 43 |
44 | #+end_export 45 | 46 | [fn:3] /eval/apply/ and /learn generously/ pervade all that I 47 | [[./posts/index.html][think]], [[https://github.com/adityaathalye/clojure-by-example][teach]], 48 | [[https://confengine.com/user/aditya-athalye-1][speak]], [[https://inclojure.org/][organise]], 49 | [[https://news.ycombinator.com/submitted?id=adityaathalye][share]], [[https://github.com/adityaathalye/][code]]. 50 | 51 | [fn:4] 52 | If you fancy /The Rather Occasional eval/apply Dispatch/, get yours here... 53 | #+begin_export html 54 | 64 | #+end_export 65 | Or just [[mailto:hello@evalapply.org][write to me]]. I love slow-mo, thoughtful email banter. 66 | -------------------------------------------------------------------------------- /sources/now.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Eval/Apply for fun and profit. 3 | #+summary: A now page inspired by sive.rs/now and nownownow.com 4 | #+author: Adi 5 | #+tags: now 6 | #+date: 2023-03-24 7 | # SHITE_META 8 | 9 | ----- 10 | * What I am doing /now/ [fn:1] 11 | 12 | #+begin_quote 13 | “I want to stay as close to the edge as I can without going over. Out on the edge 14 | you see all kinds of things you can't see from the center.” ― Kurt Vonnegut 15 | #+end_quote 16 | 17 | * 2023 18 | 19 | /Updated:/ Aug 2023 (prev: May 2023) 20 | 21 | Starting July, I have been back at the [[#section-1][Recurse Center]] for a programmer's 22 | retreat. RC is my favourite community of gentlenerds, and it's fantastic 23 | to be in NYC again, among all these awesome people. 24 | 25 | Meanwhile, the 2023 reinvention agenda continues. 26 | 27 | --- 28 | 29 | /Updated:/ May 2023 (prev: April 2023) 30 | 31 | ** 2023 is dedicated to total reinvention. 32 | 33 | A dead past is being firewalled. Accumulated baggage is being tagged for 34 | eventual garbage collection. The mind's mechanics are being revised. The body is 35 | being repaired and upgraded. New experiences are being opted into. By learning 36 | to see with new eyes, a fresh vision of self, world, and life is appearing. 37 | 38 | #+begin_quote 39 | *Analogy:* Adopt "diffuse mode" mindset to reinvent, and "focus mode" mindset 40 | to then re-build. 41 | #+end_quote 42 | 43 | ** 2023 is professional reinvention number three. 44 | 45 | My 20s were full of MBA-type work as well as one failed attempt at a startup. 46 | My 30s became about software engineering. The 40s seem to have begun with yet 47 | another pivot; toward solo enterprise. Suit and hoodie are amalgamating. 48 | 49 | #+begin_quote 50 | *Objective:* Test one's wits, skills, capabilities, knowledge in the exacting 51 | crucible of makin' and sellin' stuff. 52 | #+end_quote 53 | 54 | ** 2023 is sabbatical number four. 55 | 56 | My sabbaticals have been times of hardcore reading, study, and hands-on 57 | use of new knowledge. Literally living /eval/apply/; I learn things and 58 | test myself by landing paid gigs for what I have learned. Let's see where this 59 | one goes. 60 | 61 | #+begin_quote 62 | *Insight:* Making sabbaticals work is primarily about psychology, not money. 63 | #+end_quote 64 | 65 | ** Yes, and... 66 | 67 | An improv-style approach is being applied to break into the present, and to also 68 | break out of the "no, but" style psychological ossification that is common 69 | experience, after having lived a bit (but not a bit too much). Living a bit too 70 | much seems to engender a "like, whatever" style of psychological regression. 71 | That feels /so/ much harder to escape. Anyway, we're escaping "no, but" out here, 72 | and if you call this method improv-ing oneself, we won't complain. 73 | 74 | #+begin_quote 75 | *Experience:* I am about a year into what I've dubbed the "/Yes, and/ method of 76 | reinvention". And yes, I heartily recommend it to anyone who will listen. 77 | #+end_quote 78 | 79 | ** Small is beautiful; the lifelong trend continues. 80 | 81 | Career-start was the first time I truly exerted my volitional muscles, and chose 82 | to work with/at small and medium companies instead of the socially approved giant 83 | MNC circuit. That drive has run through my MBA twenties, tech thirties, and seems 84 | to be the /telos/ for the, shall we say, /[[https://goodreads.com/book/show/37570605-company-of-one][company of one]]/ forties? 85 | 86 | #+begin_quote 87 | *Principle:* When reinventing, known-good legacy need not be discarded. 88 | It may in fact be the very thing to subtract down to, and rebuild from, anew. 89 | #+end_quote 90 | 91 | * 2021 and 2022 92 | 93 | #+begin_quote 94 | "A rebirth requires a death." 95 | 96 | --- Yours truly 97 | #+end_quote 98 | 99 | 'nuff said. 100 | 101 | * 2020 102 | 103 | /This/ would be /The Year Of Total Reinvention/, had Certain World Events 104 | not intervened. Still, it began swimmingly, hacking Clojure code at a consulting 105 | gig, organising [[https://inclojure.org/][IN/Clojure 2020]], and experiencing 106 | an amazing programmer's retreat at the Recurse Center [fn:2]. 107 | 108 | * Pre-2020 109 | 110 | Faded into the mists of time. [[#what-i-am-doing-now][GOTO now]]. 111 | 112 | [fn:1] 113 | #+begin_quote 114 | "This is [[https://nownownow.com/about][a now page]], and if you have your own site, 115 | [[https://nownownow.com/about][you should make one]], too." --- [[https://sive.rs/now][Derek Sivers]] 116 | #+end_quote 117 | 118 | [fn:2] RC is /the retreat where curious programmers recharge and grow/. 119 | #+begin_export html 120 |
121 | 122 | #+end_export 123 | -------------------------------------------------------------------------------- /sources/posts/animate-text-art-javascript/DarkDrawSheetView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/animate-text-art-javascript/DarkDrawSheetView.png -------------------------------------------------------------------------------- /sources/posts/animate-text-art-javascript/HanukkahOfData2022ArtCopyrightDwimmertxt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/animate-text-art-javascript/HanukkahOfData2022ArtCopyrightDwimmertxt.png -------------------------------------------------------------------------------- /sources/posts/animate-text-art-javascript/HanukkahOfData2022ArtSliceCopyrightDwimmertxt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/animate-text-art-javascript/HanukkahOfData2022ArtSliceCopyrightDwimmertxt.png -------------------------------------------------------------------------------- /sources/posts/animate-text-art-javascript/HanukkahOfData2022DarkDrawDrawingViewCopyrightDwimmer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/animate-text-art-javascript/HanukkahOfData2022DarkDrawDrawingViewCopyrightDwimmer.png -------------------------------------------------------------------------------- /sources/posts/animate-text-art-javascript/HanukkahOfData2022DarkDrawSheetViewCopyrightDwimmer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/animate-text-art-javascript/HanukkahOfData2022DarkDrawSheetViewCopyrightDwimmer.png -------------------------------------------------------------------------------- /sources/posts/animate-text-art-javascript/blink.ddw: -------------------------------------------------------------------------------- 1 | {"id": "0", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 2 | {"id": "1", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 3 | {"x": 0, "y": 0, "text": "0", "color": "", "tags": [], "group": "", "frame": "0"} 4 | {"x": 0, "y": 0, "text": "=", "color": "", "tags": [], "group": "", "frame": "1"} 5 | -------------------------------------------------------------------------------- /sources/posts/animate-text-art-javascript/glider.ddw: -------------------------------------------------------------------------------- 1 | {"id": "0", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 2 | {"id": "1", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 3 | {"id": "2", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 4 | {"id": "3", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 5 | {"id": "4", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 6 | {"x": 1, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 7 | {"x": 1, "y": 2, "text": "#", "color": "", "tags": [], "group": "", "frame": "0"} 8 | {"x": 1, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 9 | {"x": 1, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 10 | {"x": 2, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 11 | {"x": 2, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 12 | {"x": 2, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 13 | {"x": 2, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 14 | {"x": 2, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 15 | {"x": 3, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 16 | {"x": 3, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 17 | {"x": 3, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 18 | {"x": 3, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 19 | {"x": 4, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 20 | {"x": 4, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 21 | {"x": 4, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 22 | {"x": 4, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 23 | {"x": 1, "y": 2, "text": "#", "color": "", "tags": [], "group": "", "frame": "0"} 24 | {"x": 1, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 25 | {"x": 1, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 26 | {"x": 1, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 27 | {"x": 1, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 28 | {"x": 2, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 29 | {"x": 2, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 30 | {"x": 2, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 31 | {"x": 2, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 32 | {"x": 3, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 33 | {"x": 3, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 34 | {"x": 3, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 35 | {"x": 3, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 36 | {"x": 4, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 37 | {"x": 4, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 38 | {"x": 4, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 39 | {"x": 4, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "1"} 40 | {"x": 1, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 41 | {"x": 1, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 42 | {"x": 1, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 43 | {"x": 1, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 44 | {"x": 2, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 45 | {"x": 2, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 46 | {"x": 2, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 47 | {"x": 2, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 48 | {"x": 3, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 49 | {"x": 3, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 50 | {"x": 3, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 51 | {"x": 3, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 52 | {"x": 4, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 53 | {"x": 4, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 54 | {"x": 4, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 55 | {"x": 4, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 56 | {"x": 1, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 57 | {"x": 1, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 58 | {"x": 1, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 59 | {"x": 1, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 60 | {"x": 2, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 61 | {"x": 2, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 62 | {"x": 2, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 63 | {"x": 2, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 64 | {"x": 3, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 65 | {"x": 3, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 66 | {"x": 3, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 67 | {"x": 3, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 68 | {"x": 4, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 69 | {"x": 4, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 70 | {"x": 4, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 71 | {"x": 4, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "3"} 72 | {"x": 1, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 73 | {"x": 1, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 74 | {"x": 1, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 75 | {"x": 1, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 76 | {"x": 2, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 77 | {"x": 2, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 78 | {"x": 2, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 79 | {"x": 2, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 80 | {"x": 3, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 81 | {"x": 3, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 82 | {"x": 3, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 83 | {"x": 3, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 84 | {"x": 4, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 85 | {"x": 4, "y": 2, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 86 | {"x": 4, "y": 3, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 87 | {"x": 4, "y": 4, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 88 | {"x": 2, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "0"} 89 | {"x": 3, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "0"} 90 | {"x": 3, "y": 2, "text": "#", "color": "", "tags": [], "group": "", "frame": "0"} 91 | {"x": 3, "y": 1, "text": "#", "color": "", "tags": [], "group": "", "frame": "0"} 92 | {"x": 2, "y": 1, "text": "#", "color": "", "tags": [], "group": "", "frame": "1"} 93 | {"x": 3, "y": 2, "text": "#", "color": "", "tags": [], "group": "", "frame": "1"} 94 | {"x": 4, "y": 2, "text": "#", "color": "", "tags": [], "group": "", "frame": "1"} 95 | {"x": 3, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "1"} 96 | {"x": 2, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "1"} 97 | {"x": 2, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "2"} 98 | {"x": 3, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "2"} 99 | {"x": 4, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "2"} 100 | {"x": 4, "y": 2, "text": "#", "color": "", "tags": [], "group": "", "frame": "2"} 101 | {"x": 3, "y": 1, "text": "#", "color": "", "tags": [], "group": "", "frame": "2"} 102 | {"x": 2, "y": 2, "text": "#", "color": "", "tags": [], "group": "", "frame": "3"} 103 | {"x": 4, "y": 2, "text": "#", "color": "", "tags": [], "group": "", "frame": "3"} 104 | {"x": 4, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "3"} 105 | {"x": 3, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "3"} 106 | {"x": 3, "y": 4, "text": "#", "color": "", "tags": [], "group": "", "frame": "3"} 107 | {"x": 2, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "4"} 108 | {"x": 3, "y": 4, "text": "#", "color": "", "tags": [], "group": "", "frame": "4"} 109 | {"x": 4, "y": 4, "text": "#", "color": "", "tags": [], "group": "", "frame": "4"} 110 | {"x": 4, "y": 3, "text": "#", "color": "", "tags": [], "group": "", "frame": "4"} 111 | {"x": 4, "y": 2, "text": "#", "color": "", "tags": [], "group": "", "frame": "4"} 112 | {"x": 1, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 113 | {"x": 1, "y": 1, "text": "-", "color": "", "tags": [], "group": "", "frame": "4"} 114 | -------------------------------------------------------------------------------- /sources/posts/animate-text-art-javascript/loading.ddw: -------------------------------------------------------------------------------- 1 | {"x": 0, "y": 0, "text": "=", "color": "", "tags": [], "group": ""} 2 | {"x": 1, "y": 0, "text": ".", "color": "", "tags": [], "group": ""} 3 | {"x": 2, "y": 0, "text": "+", "color": "", "tags": [], "group": ""} 4 | {"x": 3, "y": 0, "text": "-", "color": "", "tags": [], "group": ""} 5 | -------------------------------------------------------------------------------- /sources/posts/animate-text-art-javascript/spinner.ddw: -------------------------------------------------------------------------------- 1 | {"id": "0", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 2 | {"id": "1", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 3 | {"id": "2", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 4 | {"id": "3", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 5 | {"id": "4", "type": "frame", "text": "", "color": "", "tags": [], "group": "", "duration_ms": 100} 6 | {"x": 0, "y": 0, "text": "-", "color": "", "tags": [], "group": "", "frame": "0"} 7 | {"x": 0, "y": 0, "text": "/", "color": "", "tags": [], "group": "", "frame": "1"} 8 | {"x": 0, "y": 0, "text": "-", "color": "", "tags": [], "group": "", "frame": "2"} 9 | {"x": 0, "y": 0, "text": "\\", "color": "", "tags": [], "group": "", "frame": "3"} 10 | {"x": 0, "y": 0, "text": "+", "color": "", "tags": [], "group": "", "frame": "4"} 11 | -------------------------------------------------------------------------------- /sources/posts/bad-matrix/bad_matrix_demo.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/bad-matrix/bad_matrix_demo.webm -------------------------------------------------------------------------------- /sources/posts/bad-matrix/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Bad Matrix 3 | #+summary: A while ago, someone in the Recurse Center nerdiverse decided we needed a "Bad Print". They made one. Things escalated. Bad Matrix happened. 4 | #+author: Adi 5 | #+date: 2023-02-14 6 | #+updated: 2023-02-14 7 | #+tags: riff bash 8 | #+include_toc: yes 9 | # SHITE_META 10 | 11 | #+html: 14 | It would never have seen light of day, but fate intervened. The overlords at 15 | /NebCorp Heavy Industries and Sundries/ recently chose to emblogginate and 16 | [[https://proclamations.nebcorp-hias.com/sundries/shit-code-and-performance-art/#bad-print-a-silly-program][resurrect the long-dead Bad Print thread]] (pun intended). 17 | * Prologue 18 | Back then, thoughts originally appeared encoded in Haskell, prompting the dear 19 | reader this way... 20 | 21 | #+begin_quote 22 | you probably didn't know that you needed a bad print function, one that spawns a 23 | thread for each character in your string and prints the single character before 24 | quitting... well, now that you know that you needed this, i've written one for you 25 | 26 | #+begin_src shell 27 | $ cat <bad-print.hs 28 | > import qualified Control.Concurrent.Async as A 29 | > import qualified System.Environment as E 30 | > 31 | > main = head <$> E.getArgs >>= A.mapConcurrently putChar 32 | > EOF 33 | $ ghc -threaded -rtsopts -with-rtsopts=-N bad-print.hs 34 | [1 of 1] Compiling Main ( bad-print.hs, bad-print.o ) 35 | Linking bad-print ... 36 | 37 | $ ./bad-print 'hello there, world' 38 | h telloehre, world 39 | $ ./bad-print 'oops, i think you meant *hello there, world*' 40 | oops, i tihnk you meant *hello there ,owrld* 41 | $ ./bad-print "that's more like it" 42 | st at'hmore likei t 43 | #+end_src 44 | 45 | i wonder what bad print looks like in your language of choice? 46 | #+end_quote 47 | 48 | ... and the original thread begat replies in Rayon, Ruby, Bash, C (repeatedly). 49 | 50 | People rapidly converged to ~Thread Per Character~ as the one true performance 51 | metric for /bad print/. A Bash version claiming to provide /bad print/ for all 52 | Unixen fetched the indignation of a resident ~ksh~ user, who filed a defect report 53 | that not every Unix comes with Bash installed by default. 54 | 55 | They are, of course, all correct in their own ways. 56 | 57 | Yours truly contributed their very forgettable version of /bad print/. Which is 58 | why it does not feature here. /However/ for equally forgettable reasons --- a large 59 | volume of coffee may have been involved --- in a fit of wild fancy, that guy flew 60 | off on a completely uncalled for tangent and brought forth /Bad Matrix/. And this 61 | guy is not one to shy away from nerdsniping you into code riffing your own bad 62 | whatever. 63 | 64 | So here it is --- /Bad Matrix/ as a function --- copied below in its entirety to 65 | enjoy safely in your own home, in your own jammies, in your own terminal emulator. 66 | * Bad Matrix 67 | #+begin_src bash 68 | bad_matrix() { 69 | local cols=$(tput cols) 70 | local rows=$(tput lines) 71 | 72 | __parse_chars() { 73 | LANG="en_US.UTF-8" sed -e 's/\(.\)/\1\n/g' & 74 | } 75 | 76 | __maybe_dim() { 77 | if [[ $(( ${RANDOM} % 3 )) == 0 ]] 78 | then tput dim 79 | else tput sgr0 80 | fi 81 | } 82 | 83 | __colour_me_matrix() { 84 | __maybe_dim 85 | tput setaf 2 86 | } 87 | 88 | __maybe_goto_Y() { 89 | local y_pos=$(( ${RANDOM} % ${rows} )) 90 | if [[ $(( ${RANDOM} % 2 )) == 0 ]] 91 | then tput cup ${y_pos} 0 92 | fi 93 | } 94 | 95 | __print_chars_slowly() { 96 | while read char; 97 | do printf "%q" "$char" | sed -e "s/''/ /g" & 98 | done 99 | } 100 | 101 | __inject_matrix() { 102 | local __hundred_common_kanji_apparently="日 一 大 年 中 会 人 本 月 長 国 出 上 十 生 子 分 東 三 行 同 今 高 金 時 手 見 市 力 米 自 前 円 合 立 内 二 事 社 者 地 京 間 田 体 学 下 目 五 後 新 明 方 部 .女 八 心 四 民 対 主 正 代 言 九 小 思 七 山 実 入 回 場 野 開 万 全 定 家 北 六 問 話 文 動 度 県 水 安 氏 和 政 保 表 道 相 意 発 不 党" 103 | local __rand_chars=$(( 1 + ${RANDOM} % ${cols} )) 104 | 105 | if [[ $(( ${RANDOM} % 3 )) == 0 ]] 106 | then tput el 107 | else __maybe_goto_Y 108 | __colour_me_matrix 109 | 110 | read -n ${__rand_chars} __character_fragment <<<${__hundred_common_kanji_apparently} 111 | 112 | for c in ${__character_fragment} 113 | do sleep 0.05 114 | printf "%s " "${c}" > /dev/tty & 115 | done 116 | fi 117 | } 118 | 119 | __print_line_fragment() { 120 | local __rand_chars=$(( 1 + ${RANDOM} % ${cols} )) 121 | while read -n ${__rand_chars} line ; 122 | do sleep 0.5 123 | __maybe_goto_Y 124 | __inject_matrix 125 | tput dim 126 | printf "%s\n" "$( __parse_chars <<<"${line}" | __print_chars_slowly )" & 127 | done 128 | } 129 | 130 | cat /dev/urandom | __print_line_fragment 131 | } 132 | #+end_src 133 | * Epilogue 134 | The resurrected thread caused a fellow Recurser to emit a ~bad_cat~ in Rust. I'm 135 | not sure of this choice of tool. Being a famously memory safe language, I worry 136 | they will be unable to write a truly bad bad cat. But I could be wrong. Interested 137 | parties may [[https://github.com/MikkelPaulson/badcat/issues][peruse of their issues]] on Github. 138 | 139 | /Fin./ 140 | -------------------------------------------------------------------------------- /sources/posts/cold-restart-total-outage/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Cold restart whole system after total outage 3 | #+summary: "What are folks’ views on systems so large where cold-starting the whole system is almost impossible?"... — M'colleague, Shivam, In A Slackroom Next Door. 4 | #+author: Adi 5 | #+date: 2023-04-07 6 | #+updated: 2023-07-23 7 | #+tags: riff systems complexity meta 8 | #+include_toc: no 9 | # SHITE_META 10 | 11 | #+begin_quote 12 | ... When all your systems go down because data center blew up or something else 13 | happened which caused all the fancy microservices, IAM, etc etc are dead. 14 | 15 | ... I got interested in this (sic) disaster recovery methods when Elon Musk 16 | started laying off the bird app’s employees and everyone was saying twitter will 17 | go down and it will be almost impossible to cold start it." 18 | 19 | --- M'colleague, [[https://twitter.com/shivam_310][Shivam Singhal]] , spake further 20 | #+end_quote 21 | 22 | Nerdsnipe! 23 | 24 | And so /of course/ one ends up riffing off a blog-length wall of text. Which you 25 | can read, right here... 26 | 27 | --- 28 | 29 | Well... a former boss told me this story about his time at a giant US telco, 30 | back in the mid/late 1990s. 31 | 32 | People up-high initiated some major org restructure. In the course of 33 | housekeeping, he / his team found an absolutely giant shell script (10K LoC types, IIRC). 34 | 35 | It was called DISASTER. Yes, in all caps. 36 | 37 | There was no documentation, obviously. So they asked around and found nobody knew 38 | anything inside the org. And then some old timer said to contact "Bill", a 39 | retired old timer to ask if he knew anything. The moment "Bill" heard that 40 | someone was planning to trash the script he yelled "Don't do that!!!". 41 | 42 | It turned out that the script was the only thing that knew how to bootstrap the 43 | Telco's entire system from scratch in the event of a total continent-wide 44 | disaster/outage. Right from finding switches and network equipment/hardware to 45 | recover/restart, in what sequence etc. 46 | 47 | The script was authored sometime in the 1980s. 48 | 49 | --- 50 | 51 | #+begin_quote 52 | What are folks’ views on systems so large where cold-starting the whole system 53 | is almost impossible? 54 | #+end_quote 55 | 56 | I'd be surprised if there existed a system where cold-starting it is /impossible/. 57 | 58 | I'd agree it would be impossible to restore it to its former shape and state. 59 | 60 | Evolution, for example, has shown itself to be surprisingly resilient, having 61 | come back from near-zero not just once, but several times. 62 | 63 | It's a very interesting line of questioning. 64 | 65 | Consider what would it take to reboot civilization as we know it? It /is/ a 66 | system, make no mistake. 67 | 68 | One insight that bowls me over is, we would need to recover the ability to make 69 | precision screws (as in precision threading). 70 | 71 | So much of the modern world depends on our mastery over materials (to make a 72 | precision screw, you need a precision-machined harder material---diamond / 73 | titanium---to work on a softer material---steel), and our ability to turn rotary 74 | motion to linear motion (it's stupidly difficult to reliably precision-machine a 75 | harder material without even more precise linear + rotary motion---lathe/CNC 76 | machine). Hence, a bootstrap problem. 77 | 78 | In fact, I'd recommend looking /way/ outside software to see how people think 79 | about recovering from catastrophic losses / shutdowns. Electric grid systems, 80 | supply chains, political succession, military planning, medicine and so forth. 81 | 82 | One of the common lessons is to compartmentalise, so that at least something can 83 | be restored. Another is to have some sort of self-diagnosis going on so that one 84 | can do something at least while the whole thing is going down. A third is to have 85 | a seed of a backup---memory and know-how---from which to restore the atomic parts 86 | of the thing. 87 | 88 | None of this works if there is no disaster plan, btw. Even though nothing will 89 | go as planned, it's important to have the memory and expertise that did the 90 | planning, becuase that's what's going to be able to think through the as-yet- 91 | unknown-unknowns, when the inevitable FUBAR situation suddenly happens later. 92 | 93 | Apropos long-range planet-scale disaster planning + execution, H.E.B.'s story is 94 | one of the more interesting stories I came across: 95 | 96 | #+begin_quote 97 | [[https://www.texasmonthly.com/food/heb-prepared-coronavirus-pandemic/][Inside the Story of How H-E-B Planned for the Pandemic]] 98 | 99 | The grocer started communicating with its Chinese counterparts in January and 100 | was running tabletop simulations a few weeks later. (But nothing prepared it for 101 | the rush on toilet paper.) 102 | 103 | --- By Dan Solomon and Paula Forbes, March 26, 2020, Texas Monthly 104 | #+end_quote 105 | 106 | --- 107 | 108 | Another colleague in the chat remarked up-thread (apropos cold reboot thinking): 109 | 110 | #+begin_quote 111 | I have seen this at and at . 112 | Most of it is related to cached data. Cold starts with empty caches causes too 113 | much load on databases. And then the failures cascade. 114 | 115 | --- Another M'colleague in the Slackroom. 116 | #+end_quote 117 | 118 | Not at all ironically, I've seen this at home. Thanks to the Indian Navy 119 | background, we keep semi-annually-revised "death files" at home. A very 120 | practical, not at all morbid (despite the name), response to the uncertainty of 121 | the human organism's uptime. 122 | 123 | On the occurrence of the inevitable, one can't restore the family system to it's 124 | former state, but one can restore a lot of mechanical functionality. 125 | 126 | The same thinking applies --- backups/nominations, succession planning and 127 | transfers of ownership and control, post-hoc admin action items etc. 128 | 129 | --- 130 | 131 | #+begin_quote 132 | What are folks’ views on systems so large where cold-starting the whole system 133 | is almost impossible? 134 | #+end_quote 135 | 136 | Suffice to say, I think of it as systems so /complex/ where cold-starting is 137 | highly improbable, and restoring to former state is impossible (because, entropy). 138 | 139 | Ask a heart surgeon trying to save a person's life. They literally cold-reboot people! 140 | 141 | I can be convinced to argue that---barring a few exceptions, like the Internet 142 | and the WWW---the software systems we create are /tame/ complexity-wise, compared 143 | to organic / social systems. 144 | 145 | In abstract terms, many Google-likes and Apple-likes and Amazon-likes are 146 | possible. i.e. if you hard-stopped one of those, odds are you can re-create 147 | things that behave like those. You are guaranteed to never get back exactly 148 | Google, or Apple, or Aamzon. But you can ground-up create verisimilar entities. 149 | They've happened, in fact (Yahoo, Nokia, Baidu, Yandex, Alibaba, Samsung, 150 | etc.). 151 | 152 | The Internet/WWW is orders of magnitude harder to recreate. But maybe also 153 | orders of magnitude harder to prevent permanently... 154 | 155 | To prevent the Internet from happening---the entire computer industry for that 156 | matter---we'd have to go back very far in history and punch people in the face 157 | just before they got excellent insights. Like electromagnetism, fourier 158 | transforms, quantum mechanics, and so forth---and that's just the electrical 159 | engineering parts. 160 | 161 | And it still wouldn't guarantee the prevention of some kind of planet-scale 162 | Inter-networked communication system. (Due to the fallacy of the "Great man" 163 | hypothesis.) 164 | 165 | Tying electrical + quantum mechanical engineering back up-thread to the point 166 | about precision screws, and rotory control, hard drives present themselves as an 167 | interesting case study... 168 | 169 | #+begin_quote 170 | [[https://hackaday.com/2020/09/23/hard-disk-drives-have-made-precision-engineering-commonplace/][Hard Disk Drives Have Made Precision Engineering Commonplace]] 171 | 172 | Modern-day hard disk drives (HDDs) hold the interesting juxtaposition of being 173 | simultaneously the pinnacle of mass-produced, high-precision mechanical 174 | engineering, as well as the most scorned storage… 175 | #+end_quote 176 | 177 | And at this point I realised... 178 | 179 | #+begin_quote 180 | Hey, I just wrote a blog post :p :) 181 | #+end_quote 182 | 183 | and stopped the wall-of-texting. /But/ you and I can keep riffing, if you like 184 | long-running email conversations... 185 | 186 | #+html:
187 | #+html:
188 | See [[https://news.ycombinator.com/item?id=36792421][discussion at HN]]. Several cool anecdotes and some useful critiques. 189 | #+html:
190 | #+html:
191 | -------------------------------------------------------------------------------- /sources/posts/dismal-arithmetic-dyalog-apl-clojure/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Dismal Arithmetic in Dyalog APL and Clojure 3 | #+summary: Dismal arithmetic is just like the arithmetic you learned in school, only simpler: there are no carries, when you add digits you just take the largest, and when you multiply digits you take the smallest. How does code look in the two languages I like a lot; Clojure and APL? 4 | #+author: Adi 5 | #+date: 2022-02-25 6 | #+updated: 2022-02-25 7 | #+tags: clojure apl functional_programming riff 8 | #+include_toc: yes 9 | # SHITE_META 10 | 11 | --- /Throwback: Jan 2018./ --- 12 | 13 | I learned of /[[https://arxiv.org/abs/1107.1130][Dismal Arithmetic]]/ from [[https://twitter.com/rdivyanshu][@rdivyanshu]] who posed it as a 14 | programming problem in a Slackroom of local gentlenerds. 15 | 16 | As the linked paper describes it: 17 | 18 | #+begin_quote 19 | Dismal arithmetic is just like the arithmetic you learned in school, only 20 | simpler: there are no carries, when you add digits you just take the largest, 21 | and when you multiply digits you take the smallest. This paper studies basic 22 | number theory in this world, including analogues of the primes, number of 23 | divisors, sum of divisors, and the partition function. 24 | #+end_quote 25 | 26 | I thought it might be fun to implement it in APL for kicks, but I wrote it in 27 | Clojure first, because I wasn't sure of my APL-fu. And I'm glad I wrote the 28 | Dyalog APL version because I learned something about trains, and also because 29 | I stumbled on the idea of "inverse of a function" which melted my mind a bit. 30 | 31 | * Examples of Dismal Addition and Multiplication 32 | OK, so first, a disclaimer. The code doesn't explore all of the paper, just 33 | addition, multiplication along with commutative, associative, distributive 34 | properties thereof, because that's all the Mathematics I understand :) I had 35 | fun struggling through the paper anyway mainly because of the funny name. 36 | (More papers should have more wryness and less dryness.) 37 | 38 | Anyway, the rules of the game are: 39 | - arithmetic as in school, except that 40 | - there there are no carries, 41 | - when you add digits you just take the largest, 42 | - and when you multiply digits you take the smallest 43 | 44 | Dismal addition: 169 + 248 = 269, because... 45 | #+begin_src text 46 | 1 6 9 47 | + 2 4 8 48 | ------- 49 | 2 6 9 50 | #+end_src 51 | 52 | Dismal Multiplication: 169 * 248 = 12468, because... 53 | 54 | #+begin_src text 55 | 1 6 9 56 | x 2 4 8 57 | --------- 58 | 1 6 8 59 | 1 4 4 60 | 1 2 2 61 | --------- 62 | 1 2 4 6 8 63 | #+end_src 64 | 65 | The tasks: 66 | - Write function for dismal addition 67 | - Takes two positive integer returns dismal sum 68 | - Write function for dismal multiplication 69 | - Takes two positive integer returns dismal multiplication 70 | * Dismal Arithmetic in Clojure 71 | Here I explored the basic properties of addition and multiplication. Yeah, 72 | sorry got to slog through some encoding/decoding prerequisites first. 73 | 74 | #+begin_src clojure 75 | (ns dismal-arithmetic) 76 | 77 | (defn n->digits 78 | "Really dismal :sobbing: 79 | Will turn the number 12345 into the sequence (1 2 3 4 5)." 80 | [n] 81 | (loop [n n 82 | xs (list)] 83 | (if (< n 10) ; ensure we split 10 also, into 1 and 0 84 | (conj xs (-> n Math/floor Math/round)) 85 | (recur (/ n 10) 86 | (conj xs 87 | (-> n (rem 10) Math/floor Math/round)))))) 88 | 89 | ;; Check... 90 | #_(map n->digits [169 248 100 10 1 0]) 91 | 92 | 93 | (defn digits->n 94 | "Will turn the sequence (1 2 3 4 5) into the number 12345." 95 | [dxs] 96 | (reduce (fn [r dx] (+ (* r 10) dx)) 97 | dxs)) 98 | 99 | 100 | (defn dismal-add 101 | "x and y can have any number of digits" 102 | [x y] 103 | (let [nxs (n->digits x) 104 | nys (n->digits y) 105 | cxs (count nxs) 106 | cys (count nys) 107 | dxys (Math/abs (- cxs cys)) 108 | dzs (repeat dxys 0) 109 | [nxs nys] (if (> cxs cys) 110 | [nxs (concat dzs nys)] 111 | [(concat dzs nxs) nys])] 112 | (->> nys 113 | (map max nxs) 114 | digits->n))) 115 | 116 | 117 | (defn dismal-mul 118 | "Like politics and war, multiplication is just addition 119 | by other means. No?" 120 | [x y] 121 | (let [nxs (n->digits x) 122 | nys (n->digits y) 123 | diagonal-summable 124 | (reduce (fn [rs y] 125 | (conj rs (map #(min y %) nys))) 126 | [] 127 | nxs) 128 | transpose-matrix (fn [matrix] 129 | (into [] 130 | (apply map vector matrix))) 131 | summable-matrix (transpose-matrix diagonal-summable) 132 | summables (reverse (map digits->n summable-matrix)) 133 | summables (map-indexed (fn [idx x] 134 | (* x (Math/round (Math/pow 10 idx)))) 135 | summables)] 136 | (reduce dismal-add summables))) 137 | 138 | 139 | (comment 140 | ;; Given test cases: 141 | (= (dismal-add 169 248) 142 | 269) 143 | 144 | (= (dismal-mul 169 248) 145 | 12468) 146 | 147 | ;; Other numbers: 148 | (dismal-add 123 45678) 149 | (dismal-mul 123 45678) 150 | 151 | 152 | ;; Associative? 153 | 154 | (= (dismal-add 169 (dismal-add 248 100)) 155 | (dismal-add (dismal-add 169 248) 100)) 156 | 157 | (= (dismal-mul 169 (dismal-mul 248 100)) 158 | (dismal-mul (dismal-mul 169 248) 100)) 159 | 160 | 161 | ;; Commutative? 162 | 163 | (= (reduce dismal-add [169 248 12345]) 164 | (reduce dismal-add [248 12345 169]) 165 | (reduce dismal-add [12345 169 248])) 166 | 167 | (= (reduce dismal-mul [169 248 12345]) 168 | (reduce dismal-mul [248 12345 169]) 169 | (reduce dismal-mul [12345 169 248])) 170 | 171 | 172 | ;; Distributive? 173 | 174 | (= (dismal-mul 100 175 | (dismal-add 169 248)) 176 | 177 | (dismal-add (dismal-mul 100 169) 178 | (dismal-mul 100 248))) 179 | ) 180 | #+end_src 181 | 182 | * Dismal Arithmetic in Dyalog APL 183 | Here, I managed to implement addition, discovered how to write "inverse of a 184 | function" and my mind melted. 185 | 186 | #+begin_src dyalog 187 | da ← 10⊥(⌈/10⊥⍣¯1⊢) 188 | da 169 248 189 | 269 190 | #+end_src 191 | 192 | Yes, that's the entire solution to dismal addition. ~⍣¯1~ is APL for "inverse". 193 | Here is the solution explained in parts. I first did it with dfns, because my 194 | brain is stuck inside Lisp / traditional functional programming style. 195 | 196 | Apart from built-in support for numeric encoding/decoding, notice the automatic 197 | zero-padding. 198 | 199 | #+begin_src dyalog 200 | {10(⊤⍣¯1)⍵}∘{⌈/⍵}∘{10(⊥⍣¯1)⍵}⊢ 100000 10000 1000 100 10 1 201 | 111111 202 | 203 | {10(⊤⍣¯1)⍵}∘{⌈/⍵}∘{10(⊥⍣¯1)⍵}⊢ 1 10 100 1000 10000 100000 204 | 111111 205 | 206 | da ← 10⊥(⌈/10⊥⍣¯1⊢) 207 | 208 | da 1 10 100 1000 10000 100000 209 | 111111 210 | #+end_src 211 | 212 | /However/, there is something deeply unsatisfying about using dfns in APL, when 213 | you know trains exist. 214 | 215 | So I muddled about and managed to express the whole idea as a single unit, viz. 216 | this lovely little expression ~10⊥(⌈/10⊥⍣¯1⊢)~ which says "Dismal Arithmetic" 217 | in fewer characters than the name /and is also/ a working partial implementation. 218 | Here is how it breaks down in my FP-addled brain: 219 | 220 | #+begin_src dyalog 221 | decode ← 10(⊥⍣¯1)⊢ 222 | 223 | reducemax ← ⌈/ 224 | 225 | encode ← 10(⊤⍣¯1)⊢ 226 | 227 | encode reducemax decode 169 248 228 | 269 229 | #+end_src 230 | 231 | * Addendum: The ⍣ of inverse 232 | Aaron Hsu helped me understand what was going on, and wrote about 233 | "[[https://www.sacrideo.us/decoding-inverses/][Decoding Inverses]]" at his blog. 234 | -------------------------------------------------------------------------------- /sources/posts/dont-hurry-dont-stop-sad-version/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Baby don't hurry, don't stop (feat. Melancholy) 3 | #+summary: Here lies melancholy that I put to paper from a particularly deep hole, not too long ago. It may ruin your day, or it may make you feel a little bit understood about your dark moments. Your mileage will vary. 4 | #+author: Adi 5 | #+date: 2022-02-14 6 | #+updated: 2022-02-14 7 | #+tags: meta mentalhealth 8 | #+include_toc: no 9 | # SHITE_META 10 | 11 | This is how I struggle from time to time. It is not pretty. These days it's 12 | been a lot more. Thankfully, it is not a constant. Instead of reading this, 13 | you should want to listen to Alain de Botton. 14 | - [[https://www.youtube.com/watch?v=Aw1oLtuJOXQ][on Pessimism]] 15 | - [[https://www.youtube.com/watch?v=jJ6K_f7oSdg][on Love]] 16 | - [[https://www.youtube.com/watch?v=W9X7u-MeJz0][on an Emotional Education]] 17 | 18 | For here lies melancholy that I put to paper from a particularly deep hole, 19 | not too long ago. It may ruin your day, or it may make you feel a little bit 20 | understood about your dark moments. And it---unlike Alain's teachings---will 21 | certainly not help you find a way through. 22 | 23 | Your mileage /will/ vary. 24 | 25 | Today was one of those days. 26 | 27 | When the feeling hit like a slap in the face. Again. Just how much of my 28 | youth burned in self-doubt, fear, self-shame, akrasia. 29 | 30 | Twenty years of young adulthood incinerated by mine own hand, before my own 31 | eyes, and I did nothing to save it. 32 | 33 | Sigh. 34 | 35 | This life is singular. It is not ours to have. It is not ours to end. It is 36 | ours to embrace as a gift to give away. 37 | 38 | The gift is a chance to become all that we can become. We cannot become, if we 39 | keep staring down at ourselves from imagined imaginations of others. What if 40 | I can't do it? What if I fail? What if nobody likes me? I am not /this/. I am 41 | not /that/. I'll never get /there/. /I/ am not even someone. That is the root 42 | of all self-doubt and fear and shame. A never-being in the here and now. A 43 | never-learning about oneself. A never-knowing of feeling alive. The kind of 44 | poverty that material things cannot end. 45 | 46 | Looking from the outside makes us pressure and twist ourselves into the imagined 47 | mould. But the mould changes before we're done. And we start again. The cycle is 48 | endless, relentless. We go faster, but it changes faster. And we forget ourselves. 49 | 50 | If there is one gift we can give to another, especially a young one, it would 51 | be to show them how to live this: "Don't hurry, don't stop.". To learn to /do/, 52 | without fearing the unknown, knowing failure without shame, with kindness, with 53 | oneself, without hurry. 54 | 55 | Hurry forces pause. Not pausing breaks us. So many break forever. Never becoming. 56 | 57 | So many learn too late, that they only know to hurry, that they can't slow down. 58 | Once perhaps, long ago, they peered inside their mould and saw nothing. It's 59 | not that nothing exists, it's that they never learned to see. And so all that 60 | remained was to dwell in the future; remoulding faster and faster until the 61 | breakdown. Or worse, to delve into the past, in endless revisions of discarded 62 | moulds to reach an imagined now that never will come to pass. If there is a 63 | metaverse, it is this. 64 | 65 | This prisoners' game of imagined imaginations. 66 | 67 | Fantasies rooted in fantasy. 68 | 69 | Maybe it's not too late for you. Maybe it's not too late for me. 70 | 71 | I hope it isn't. 72 | 73 | But if it is too late, then I hope we come back, you and I. 74 | 75 | For a rebirth requires a death. 76 | 77 | #+begin_quote 78 | /"It is better to do something continuously, perpetually and untiringly than to hustle and fail./ 79 | /If you hurry, you must rest. If you want to keep going without resting, then you mustn’t hurry./ 80 | 81 | /Don’t hurry, don’t stop.”/ 82 | 83 | --- [[https://en.wikipedia.org/wiki/Kintar%C5%8D_Hattori][Kintarō Hattori]] 84 | #+end_quote 85 | -------------------------------------------------------------------------------- /sources/posts/emerging-from-dotemacs-bankruptcy-getting-about/getting-about.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/emerging-from-dotemacs-bankruptcy-getting-about/getting-about.jpg -------------------------------------------------------------------------------- /sources/posts/emerging-from-dotemacs-bankruptcy-ide-experience/emacs-clojure-ide-lsp-cider-reveal-gui.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/emerging-from-dotemacs-bankruptcy-ide-experience/emacs-clojure-ide-lsp-cider-reveal-gui.jpeg -------------------------------------------------------------------------------- /sources/posts/emerging-from-dotemacs-bankruptcy-init-begins/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Emerging from dotemacs bankruptcy the hard way: init begins 3 | #+summary: The first action must, of course, be to colour the bikeshed and set some decent defaults. 4 | #+author: Adi 5 | #+date: 2023-07-04 6 | #+updated: 2023-07-04 7 | #+tags: programming emacs howto recurse_center 8 | #+include_toc: no 9 | # SHITE_META 10 | 11 | #+html:
12 | Series: 13 | [[../emerging-from-dotemacs-bankruptcy/index.html#main][prelude]] → 14 | *([[../emerging-from-dotemacs-bankruptcy-init-begins/index.html#main][init begins]])* → 15 | [[../emerging-from-dotemacs-bankruptcy-midway-refactor/index.html#main][midway refactor]] → 16 | [[../emerging-from-dotemacs-bankruptcy-packages/index.html#main][packages]] → 17 | [[../emerging-from-dotemacs-bankruptcy-getting-about/index.html#main][getting about]] → 18 | [[../emerging-from-dotemacs-bankruptcy-ide-experience/index.html#main][IDE (ft. Clojure)]] → 19 | [[https://github.com/adityaathalye/dotemacs][.emacs.d]] 20 | #+html:
21 | 22 | Jokes apart, my first action has been to read and learn from other peoples' 23 | configurations. I am referencing a small set of familiar-to-me configs I noted 24 | [[../emerging-from-dotemacs-bankruptcy/index.html][previously]]. It pays to be 25 | circumspect. One can [[https://www.emacswiki.org/emacs/ExampleConfigurations][drown in configs]]. 26 | 27 | OK, so I already have my day-to-day Emacs. It has pulled down packages, and it 28 | has set globals and so forth. I want to live-develop my new config on the same 29 | machine, without clobbering contents of the old .emacs.d, and without picking up 30 | any of my existing init files, which Emacs [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html][finds by default]] at startup. 31 | 32 | This means start a new Emacs session only with my draft init file, like so. 33 | #+begin_src shell 34 | emacs -q -l path/to/new/init.el 35 | #+end_src 36 | 37 | And I must ensure I set paths for package downloads, temporary files, and other 38 | file-based state in a safe enough way. The init file snippet below sets and/or 39 | defines values I have researched so far. The preamble and postfix to the config 40 | code is conventional Emacs-speak. An elisp package linter will complain if the 41 | information is incomplete, or the text is improper. 42 | 43 | #+html:
44 | #+html: 45 | #+html: The barebones init.el 46 | #+html:
47 | #+html:
48 | #+begin_src elisp 49 | ;;; init.el --- My Emacs configuration. 50 | 51 | ;;; Commentary: 52 | 53 | ;;; This file is not part of GNU Emacs. 54 | 55 | ;;; Author: Aditya Athalye 56 | ;;; Created on: 30 June 2023 57 | ;;; Copyright (c) 2023 Aditya Athalye 58 | 59 | ;;; License: 60 | ;;; This program is free software; you can redistribute it and/or 61 | ;;; modify it under the terms of the MIT license, which is included 62 | ;;; with this distribution. See the LICENCE.txt file. 63 | 64 | ;;; Code: 65 | 66 | ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 67 | ;; Globals 68 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 69 | 70 | ;; Always load newest byte code 71 | (setq load-prefer-newer t) ; cf. bbatsov/prelude 72 | 73 | ;; Directory structure 74 | ;; Take clues from bbatsov/prelude, except keep structure relative to our 75 | ;; initial dotemacs-dir path. This way we can start the user's emacs via 76 | ;; ~/.emacs.d symlinked to the dotemacs repo, and develop/debug against 77 | ;; the repo without potentially overwriting transient state files of the 78 | ;; daily driver .emacs.d. 79 | (defvar dotemacs-dir (file-name-directory load-file-name) 80 | "The dotemacs' root.") 81 | (defvar dotemacs-savefile-dir (expand-file-name "savefile" dotemacs-dir) 82 | "This folder stores all the automatically generated save/history-files.") 83 | (unless (file-exists-p dotemacs-savefile-dir) 84 | (make-directory dotemacs-savefile-dir)) 85 | 86 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 87 | ;; Visual Aesthetics 88 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 89 | 90 | (setq inhibit-startup-message t) 91 | 92 | ;; More screen real estate 93 | (scroll-bar-mode 0) 94 | (tool-bar-mode 0) 95 | (menu-bar-mode 0) 96 | (set-fringe-mode '(5 . 13)) ;; describe variable fringe-mode 97 | 98 | ;; Go easy on the eyes 99 | ;; This high-contrast darkmode theme is built into Emacs as of 100 | ;; Emacs version 28.1 101 | (load-theme 'modus-vivendi) 102 | 103 | 104 | (provide 'init) 105 | ;;; init.el ends here 106 | #+end_src 107 | #+html:
108 | 109 | These preliminaries /not at all obvious/---"clean GUI", garbage collection (GC) 110 | thresholds, native compilation, lockfiles, savefiles, "better defaults" settings, 111 | a decent high-contrast theme. They are "unknown unknowns". They are not easy to 112 | discover, context-free, as many functions and variables can be oddly named, and 113 | do not follow any globally standard naming convention. The manual is vast, and 114 | combing through it to learn stuff for our purpose is inadvisable. Settings are 115 | also matters of personal taste and need. This is why it helps to read different 116 | configs; to acquire context, acquire vocabulary, and to form opinions. And when 117 | tastes (or facts) change, one can always change one's mind /and/ dotemacs! 118 | 119 | The rough plan has been: 120 | - [✓] Set the very preliminaries. 121 | - Set up package management. I'll probably stick with the old familiars; elpa and 122 | melpa. I'm not sure about straight.el at this time. 123 | - Choose ~use-package~ to get and configure each package. I like how neat configs 124 | are, when defined with use-package. 125 | - Make completions and "getting about" work (the right mix of ivy, consul, 126 | swiper, company, helm, imenu). Someone mentioned newer alternatives to helm. 127 | Have a look at that. 128 | - Fix general text editing stuff (keybindings, multiple cursors, snippets etc.) 129 | - Add support for favourite programming languages. 130 | - org-mode specifics 131 | - then let's see... 132 | 133 | I feel like by this point the new init.el will be good enough to switch to, 134 | as my daily driver. Next up, package management and useful packages. 135 | -------------------------------------------------------------------------------- /sources/posts/emerging-from-dotemacs-bankruptcy/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Emerging from dotemacs bankruptcy the hard way: Prelude 3 | #+summary: Or, finally biting the bullet to redesigning my developerly and writerly experience, from the ground up, with Emacs. 4 | #+author: Adi 5 | #+date: 2023-06-29 6 | #+updated: 2023-06-29 7 | #+tags: programming emacs howto recurse_center 8 | #+include_toc: no 9 | # SHITE_META 10 | 11 | #+html:
12 | Series: 13 | *([[../emerging-from-dotemacs-bankruptcy/index.html#main][prelude]])* → 14 | [[../emerging-from-dotemacs-bankruptcy-init-begins/index.html#main][init begins]] → 15 | [[../emerging-from-dotemacs-bankruptcy-midway-refactor/index.html#main][midway refactor]] → 16 | [[../emerging-from-dotemacs-bankruptcy-packages/index.html#main][packages]] → 17 | [[../emerging-from-dotemacs-bankruptcy-getting-about/index.html#main][getting about]] → 18 | [[../emerging-from-dotemacs-bankruptcy-ide-experience/index.html#main][IDE (ft. Clojure)]] → 19 | [[https://github.com/adityaathalye/dotemacs][.emacs.d]] 20 | #+html:
21 | 22 | #+caption: [[https://xkcd.com/378/][XKCD/378]]: Real Programmers. 23 | [[https://imgs.xkcd.com/comics/real_programmers.png]] 24 | 25 | My extant Emacs configuration is built with the handy and battle tested [[https://github.com/bbatsov/prelude][prelude]] 26 | starter kit, created by indomitable Emacs fanatic and gentleman hacker, [[https://metaredux.com/about/][bbatsov]], 27 | a.k.a. "Bug", a.k.a. Bozhidar Batsov. 28 | 29 | The smart move would be to stick with /prelude/ and fix /my/ gunk instead. However, 30 | for better or worse, it is /that time/ in my developer life-cycle. The irrational 31 | gnawing urge to take it apart and rebuild it in my own image has overpowered my 32 | standard clawing reluctance to fix what ain't broke. 33 | 34 | #+caption: [[https://xkcd.com/1172/][XKCD/1172]]: Every change breaks someone's workflow. 35 | [[https://imgs.xkcd.com/comics/workflow.png]] 36 | 37 | To be honest, it has been /that time/ for a good while now. Like, years? As it 38 | happens, I had to face facts when I got serious about overhauling my Emacs config. 39 | My Emacs 26 was three major versions behind. But underneath lurked my OS, at the 40 | fag end of its LTS support window. So /of course/, the OS /had/ to be upgraded 41 | first. Two major LTS version upgrades later I had to let it rest. Then I fell 42 | into writing my [[https://github.com/adityaathalye/shite][site-maker]], because otherwise how would I blog about reduxing 43 | my dotemacs? 44 | 45 | Meanwhile, desire to actually redux my config waned. 46 | 47 | Now it waxes eloquent. 48 | 49 | Plus, I am in-batch at [[https://www.recurse.com/][the Recurse Center]], as I type this. 50 | It is a place where Yak Shaving for Joy is revered as a noble pursuit. As is 51 | proper form. 52 | 53 | Because it is our second coming, we already know we want a few things, listed 54 | below, in no particular order. 55 | - Clutter-free GUI 56 | - Easy, fast, RSI-free navigation and movement (chording, completions) 57 | - Quick, easy GUI organisation (split/move/switch/resize windows) 58 | - Awesome completions everywhere (helm and/or ivy) 59 | - Good undo/redo support (undo-tree) 60 | - Expansions and boilerplate templates (Yasnippet) 61 | - Org mode stuff (org-babel, present, export backends etc.) 62 | - Version Control (magit) 63 | - Polyglot Programming Language Support 64 | - LSP everywhere as far as possible 65 | - Clojure, MIT Scheme, Common Lisp, Bash, SQL, OCaml, APL, Java, JS, HTML, CSS, XML, YAML at least 66 | - Repo-wide refactorings 67 | - Structural code editing 68 | - Code folding 69 | - Code navigation (jump-to-definition etc.) 70 | - Auto linting 71 | - Auto formatting 72 | - Auto builds where applicable 73 | - Top notch remote REPL support (Clojure, Scheme etc.) 74 | - Multiple cursors 75 | - Diagramming 76 | - Various creature comforts 77 | - Nice theme, icons, typography 78 | - Font resizes for coding, demos, presentations 79 | - Auto save / restore files 80 | - Auto save / restore workspace 81 | - Recent files memory 82 | - ... 83 | - Maybe other use cases I don't currently employ too much 84 | - Email 85 | - PDF reading 86 | - Web browsing 87 | - etc... 88 | 89 | A partial list of references being perused in this noblest of Yak Shaves. 90 | - m'colleague [[https://github.com/suvratapte/dot-emacs-dot-d][suvrat's dotemacs]] and [[https://suvratapte.com/configuring-emacs-from-scratch-intro/][blog posts]] 91 | - m'colleague [[https://github.com/vedang/emacs-up][vedang's dotemacs]] 92 | - [[https://github.com/purcell/emacs.d][purcell's dotemacs]] 93 | - System Crafters' [[https://systemcrafters.net/emacs-from-scratch/][Emacs from scratch]] series 94 | - Mickey's mighty fine [[https://www.masteringemacs.org/][Mastering Emacs]] book 95 | - The [[https://www.gnu.org/software/emacs/manual/][Emacs Manual]] 96 | - The [[https://www.emacswiki.org/][Emacs Wiki]] 97 | 98 | Last but not least, a bankruptcy emergence requires a bankruptcy filing. The 99 | filing is hereby filed. The game is afoot. And /prelude/ remains my spiritual guide. 100 | 101 | #+begin_quote 102 | Remember that the ultimate goal of every Emacs user is to create an Emacs setup 103 | that reflects their own experience, needs, goals and ideas. Just like Lisp, Emacs 104 | is nothing but a raw building material for the perfect editing experience. 105 | 106 | --- [[https://github.com/bbatsov/prelude#philosophy][prelude's README/philosophy]] 107 | #+end_quote 108 | 109 | #+caption: [[https://xkcd.com/1205/][XKCD/1205]]: Is It Worth the Time? 110 | [[https://imgs.xkcd.com/comics/is_it_worth_the_time.png]] 111 | -------------------------------------------------------------------------------- /sources/posts/hello-world/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: In the beginning, was the domain name 3 | #+summary: How this blog came to be is a minor miracle. Long story short, I conned myself into believing nobody will find /and/ read it. But you're here, aren't you? And you're reading this. Aren't You? Confucamus. Well, here's how you got here. 4 | #+author: Adi 5 | #+tags: hello_world howto whyto 6 | #+date: 2021-11-10 7 | #+updated: 2021-11-10 8 | # SHITE_META 9 | 10 | You see, I've been... was... e-sober for a measurable fraction of the 11 | Internet era. 12 | 13 | It's been over ten years since I took down my last (and first) blog. Eight 14 | since I nuked my FB with extreme prejudice, discovering in the bargain a fine 15 | capacity for smug satisfaction, when the chagrin of aghast friends and sundry 16 | affected me not one whit. Nary a tweet-song has erupted, five years and 17 | counting. 18 | 19 | The WWW had gotten A Bit Too Much. I wanted to say nothin' to nobody on it. 20 | I was content writing the occasional long email to friends and randoms. 21 | I was /fine/. /Everything was./ 22 | 23 | Mother nature, though. She tests us. 24 | 25 | Predictably, she sprung A Rather Big Surprise at the least-convenient moment 26 | in the least-convenient century (for me, at any rate). 27 | That-which-shall-not-be-named imposed a period of involuntary house arrest. 28 | 29 | It was then, in that long dark tea time of the soul, will weakened, that I 30 | snagged a domain on impulse. 31 | 32 | This very domain. Just for my email, mind you. To de-google myself. Or something. 33 | 34 | Oh, how little did I know. [[http://garann.com/dev/2013/how-to-blog-about-code-and-give-zero-fucks/][Insidious]] [[https://sites.google.com/site/steveyegge2/you-should-write-blogs][thoughts]] [[https://applieddivinitystudies.com/2020/09/09/journaling/][started]] invading my consciousness 35 | through my soothingly red-shifted displays. The Feature Creep crept up slowly, 36 | subtly erecting neon hoardings to subvert the fog my mind had gladly embraced. 37 | /"Does your domain apologetically redirect to your github?"./ 38 | /"Your site can be more. Do more. So much more."./ 39 | /"If a reader fell upon this site and no form was around to comment in, 40 | did they make a sound?"./ 41 | Foggy the mind was, yes. 42 | 43 | That's when it gripped me. The desire to write. And it started gnawing away 44 | inside. It was all The Feature Creep's doing, of course, but I didn't know 45 | it then. 46 | 47 | Luckily, my terror of looking like an idiot--nay, an /impostor/--was far more 48 | potent than The FC's gnawing at my anemic will. I narrowly avoided working up 49 | the nerve to just point the damn domain to Wordpress and slam publish like it 50 | was 2005 again. 51 | 52 | Days turned to weeks. Weeks glommed into months. Some uncalled for hair loss 53 | occurred and a year passed. Meanwhile, the domain redirected reliably, 54 | unaware of the mayhem within and without. 55 | 56 | Still The FC gnawed on. The Feature Creep never tires, never lies down, and 57 | never dies, you see. 58 | 59 | Slyly (or so I thought), I fooled it by quietly typing into my Emacs. More 60 | days turned to weeks turned to months. Words accreted in my org-mode files. 61 | Wee notes. Snippets. Factoids squirreled away. Mostly harmless bits and bobs. 62 | Someone paying attention might have smelled trouble brewing and stopped right 63 | there. But, oh how little did I know. 64 | 65 | Unwittingly, I started penning lofty thoughts too. I caught on soon enough, 66 | but I kept doing it, despite now being acutely aware that I'd wake up feeling 67 | dirty the morning after. My confidence, though. My, did it grow supreme. It 68 | took perverse delight in jotting down opinions way above my pay grade because, 69 | after all, nobody would find out. It was all on my computer. Even if I 70 | didn't /shred/ it all, bitrot would certainly destroy every last trace of 71 | my misadventures. And I'd safely take my little secret life to my grave. 72 | Yes, I'd get away with it. 73 | 74 | But then my partner found out and started telling me things, whispering words 75 | of encouragement (somehow, /"egged on"/ seems more apt). 76 | The fault is all mine though; why we're here. For shortly after, in a 77 | momentary lapse of judgment, I also told a friend. 78 | And then, fatally, I failed to continue keeping mum before other friends. 79 | Now they want to read it all, and not privately, but "on your bloody blog, 80 | dummy". That's when I /knew/. The Feature Creep had me dead to rights 81 | from the get go. 82 | 83 | The obvious moral here is if you want to continue /not/ writing on the WWW, 84 | don't under /any/ circumstance impulse-purchase that domain, and if you do, 85 | don't secretly type in your computer, and if you do, for the love of your Gods, 86 | don't wed or befriend anyone. 87 | 88 | Anyhow, it was too late for me. Feeling suitably cornered and wretched, 89 | much moping around ensued, until it hit me; "Wait a minute, I /am/ an idiot, 90 | but I also /want/ to be [[https://danluu.com/look-stupid/][less of one]]." 91 | So this is... also fine. Maybe they will even tell me /How To Not Idiot/, if 92 | they're still here, reading. 93 | 94 | So I submitted. That domain I impulse-bought stopped redirecting, pointing 95 | to this instead. Then with infinite improbability, your browser pointed to 96 | that and served this up. And now you know exactly how you got here. And... 97 | 98 | You're still reading, aren't you? 99 | 100 | Your readership graces this site. To me, writing was thinking. Apparently it 101 | can also be a process of becoming. So thank you for being here (bows deeply). 102 | Several word collections are in progress. Please stay as long as you wish. 103 | 104 | I'll pause here to doff my hat to some heroes that I draw inspiration from; 105 | [[https://bellmar.medium.com/][bellmar]] & [[https://danluu.com][danluu]] & [[https://jvns.ca/][b0rk]] & [[https://www.gwern.net/index][gwern]] & [[https://aphyr.com/tags/writing][aphyr]] & [[https://www.kitchensoap.com/][allspaw]] & [[https://xkcd.com/][randall]] & [[https://twitter.com/foone][foone]], 106 | and a hundred more... Much to learn, have I. 107 | But we here now, an' we gon' try. We gon' try, to eval/apply. 108 | 109 | There will be some technical words, some code play, some HowTos, some WhyTos, 110 | pondering-upons of some real doozies like "Systems, Scale, Value", 111 | "Technical Debt is a CDO", "Envelope of control", "Why was the misbehaving 112 | system behaving itself?" and so forth. No pundering at all, if you're 113 | wondering. 114 | 115 | Enroute, maybe your eye catches something iffy and twitches. Perhaps a whiff 116 | of bull causes your nostrils to flare slightly. Maybe something really gets 117 | your goose and your brain screams "NO. Don't. Type. You *promised* you're 118 | done with these Internet randos who are SO BLOODY WRONG.". 119 | 120 | That's why I'm helping you by not having a comment form. 121 | 122 | But I'll be delighted to hear from you at /weblog (at) evalapply (dot) org/ 123 | if it strikes your fancy! (Or /youresobloodywrong (at) evalapply (dot) org/ 124 | if it's just /that/ kind of a day and you can't stand it any more. 125 | I know the feeling. I'm here, listening :). 126 | 127 | Thank you for swinging by! 128 | 129 | And now, /[[https://xkcd.com/386/][Duty Calls]]/. 130 | 131 | #+attr_html: :alt What do you want me to do? LEAVE? Then they'll keep being wrong! 132 | [[https://imgs.xkcd.com/comics/duty_calls.png]] 133 | -------------------------------------------------------------------------------- /sources/posts/how-to-give-a-conference-talk/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: How To Be a Totally Natural Conference Speaker? 3 | #+summary: Spurred by a conversation with a whip-smart friend and fellow gentlenerd, who unreasonably believed (believes?) they have nothing worth speaking about at the software conferences we like (IN/Clojure, FunctionalConf, local meetups etc). 4 | #+author: Adi 5 | #+date: 2022-02-03 6 | #+updated: 2022-02-03 7 | #+tags: meta writing speaking 8 | # SHITE_META 9 | 10 | A friend and I were chatting recently about speaking at conferences. Now this 11 | person is smart and I've learned a thing or two from his in-depth engineering 12 | blog posts. Yet there he was, telling me I'm so super good at communicating 13 | ideas (implying he's /not/ so super good), and besides he has nothing to say 14 | worthy of a conference talk. 15 | 16 | Huh?! 17 | 18 | Uncalled for praise is jarring, but I took it---2021 was heartless, OK? Still, 19 | the subtext of /magic/ bothered me. That I am somehow special. A born natural. 20 | So I told him my secret formula. And now I'm telling you. 21 | 22 | Here is how to be a totes natural conference speaker... 23 | 24 | 1. Mope around /all the time/ about how you don't /really/ know [Topic X]. 25 | Sooner or later an opportune Call For Proposals will slide into your Twitter 26 | stream or Slack or Discord. (It is very important to mope around /all/ the 27 | time. Also, please cultivate several topics to mope around about. This 28 | guarantees that every moment is an opportune moment to propose a talk.) 29 | 30 | 2. Foolishly jump at the chance. Write a proposal to talk (or teach a class) 31 | about said [Topic X]. 32 | 33 | 3. Congratulations! You have now made a public commitment, and opted into the 34 | specter of falling flat on your face before all and sundry. Let the feeling 35 | sink in. 36 | 37 | 4. When it does, panic and feel obligated to start making something already, 38 | because what if you can't actually figure out [Topic X]? Because then you 39 | must recuse yourself before it's too late. Proceed to have trouble starting, 40 | toss and turn in bed many nights in a row, and finally start typing 41 | something---anything---into your computer. 42 | 43 | 5. Make and trash at least 3 shitty first drafts. Feel like an impostor and 44 | /almost/ withdraw your proposal as many times. 45 | 46 | 6. If your proposal gets selected, GOTO 3 and start over. If it doesn't, GOTO 8. 47 | If you are back here after the do-over, GOTO 7. If you got here and you don't 48 | know why, well that's because GOTOs are Considered Harmful. 49 | 50 | 7. Somehow arrive at a version you don't totally hate. Then make minor edits 51 | and tweaks for days and days until you're fed up. (Actually you are fed up 52 | because the talk is just a week away by now, and you haven't rehearsed even 53 | once.) 54 | 55 | 8. Corral friends who are way smarter than you, and get them to hear you out. 56 | (Actually there's a step zero. Get very lucky in life and land up with such 57 | friends). 58 | 59 | 9. /Listen to them and don't make any more edits./ Seriously. Try to rehearse. 60 | 61 | 10. Second-guess yourself 48 hours before your talk, mid-way through your first 62 | /actual/ rehearsal. Proceed to commit the cardinal sin of refactoring the 63 | whole bloody thing "before shipping to production", because apparently it's 64 | all completely /wrong/ now. Don't sleep much, of course. 65 | 66 | 11. Wake up with a start on D-day. Curse at yourself in the mirror. Drink an 67 | unconscionable quantity of coffee, while feverishly reviewing your material. 68 | Entirely miss the "hallway track" and fail to make new friends or to have 69 | a good time. 70 | 71 | 12. Somehow make it to the other end of your presentation. It's OK, everybody 72 | forgets half the material (especially those painstakingly crafted turns of 73 | phrase and clever asides), and still somehow runs out of time. Spend the 74 | rest of the day in a growing fog because the adrenaline wore off, but the 75 | caffeine didn't, but you're wiped-out from the excitement and sleep-deprived. 76 | 77 | 13. Luckily, that also means you forget everything you did on your talk day. 78 | Now you just have to make sure you never ever watch the recording of your 79 | talk, if they publish it. 80 | 81 | 14. Bask in the certain knowledge that you too have become a 100% Totally Natural 82 | Conference Speaker. (As a veteran of this process, I can tell you it works. 83 | Every. Single. Time.) 84 | 85 | Jokes apart, it really is like that. There is no magic. Only student syndrome. 86 | 87 | Just remember that you always know more about something than someone, and/or 88 | almost certainly have a /different, unique take/ on something that you believe 89 | to be common knowledge. Not infrequently, I find someone's interpretation of 90 | something I am intimately familiar with, and the interpretation remarkably 91 | changes how I see/feel/understand/relate with the thing. (Frequently it does 92 | not, and it's rubbish, but that's fine. I'm not the one for that one.) 93 | 94 | Why? Well because no topic is objectively too small or too silly or too useless, 95 | for the right audience in the right context. 96 | Look no further than [[https://bangbangcon.com/program.html][!!Con]], for example. 97 | People have i!!ega! amounts of fun there! 98 | 99 | So do yourself a favour. Allow yourself chances to suggest your [Topic X] to 100 | the world, even when it's just your take on your favourite thing that maybe 101 | everybody already knows. Because maybe the world will say... 102 | 103 | "Sure, why not?". 104 | -------------------------------------------------------------------------------- /sources/posts/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Eval / Apply is pure magic 3 | #+summary: Stuff I like to nerd about. 4 | #+author: Adi 5 | #+tags: index 6 | #+date: 2021-11-10 7 | # SHITE_META 8 | 9 | #+begin_export html 10 |
Writing = Thinking
11 |
15 |
16 | #+end_export 17 | 18 | Hi! This is my bid to [[./hello-world/index.html#main][think in public]] and to 19 | /[[https://www.recurse.com/self-directives][learn generously]]/. Do 20 | [[mailto:weblog@evalapply.org][write to me]] if you fancy or deplore things 21 | you read here. May /The Source/ be with us! 22 | 23 | #+begin_quote 24 | “Writing is nature's way of letting you know how sloppy your thinking is.” 25 | 26 | --- Richard Guindon 27 | #+end_quote 28 | -------------------------------------------------------------------------------- /sources/posts/mycelium-clj/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Riff: A "mycelium-clj" for the Clojure ecosystem? 3 | #+summary: In a world of concrete objects, steel frameworks bring sense and order. In a forest of composable tools, libraries and open-ended schemas, it would be the mycelia. A frustrated yet optimistic man muses "Might such a thing come to be?". 4 | #+author: Adi 5 | #+date: 2023-10-19 6 | #+updated: 2023-10-20 7 | #+tags: riff clojure systems architecture recurse_center 8 | #+include_toc: no 9 | # SHITE_META 10 | 11 | A thousand library-flowers bloom, bushes and trees and vines and creepers 12 | grow, but if nothing reconnects them, the whole remains diluted and weak 13 | and unfathomable and forbidding. 14 | 15 | In a world of concrete objects, steel frameworks bring sense and order. 16 | 17 | In a forest of composable tools and libraries, it is the invisible mycelia. 18 | 19 | I am dreaming of a tool. I want to name it *mycelium-clj*. 20 | 21 | What I can't tell is if all this boils down to /"Oh look, yet another 22 | internet rando witlessly reverse-engineered a cheap knock-off of RDF/ 23 | /and the semantic web."./ Or if it is something practicable within the 24 | little village (relatively speaking) of Clojureland. 25 | 26 | Spitballing ahead! 27 | 28 | While Clojure the language itself is a joy to use, being /hosted/ means it 29 | gives us a double edged sword, with reach (yay!), but also the /compounded/ 30 | mass of the host ecosystem (Java, Javascript, .net CLR, mobile) /and/ the 31 | Clojure-specific ecosystem (REPLs, IDEs, libraries, tools). The more full 32 | stack we try to go, the more unwieldy the whole gets. 33 | 34 | For example, the joy of libraries is that you get to choose. The agony of 35 | libraries is that you /*have*/ to choose. So goes for the other chess pieces. 36 | All told it gets quite overwhelming quite fast, at least in my experience. 37 | Ultimately everyone gives up and uses the "phone a friend" option (if they 38 | even have one). 39 | 40 | Yours truly phoned his friends. 41 | 42 | A few weeks ago, I decided to jump into full stack Clojure web development 43 | for my "[[https://www.recurse.com/blog/185-do-more-than-you-think][Impossible Stuff Day]]" project at the Recurse Center. For that, 44 | I started spinning up all the machinery. And by "all" I mean the whole nine 45 | yards---working through the multifarious build tool options, REPL choices, 46 | editor options, IDE integration options (editor + build + REPL), package 47 | management tools and conventions, library options, project conventions etc. 48 | And the spinning up has spun veeeery slowly. 49 | 50 | Now, I am willing to incur the effort and hair loss to find and traverse 51 | the vast knowledge graph of all this machinery, only because I am optimistic 52 | about the (eventual) payoff. 53 | 54 | As it happens, though, I am not alone in feeling frustrated and confused. 55 | 56 | Whatsapp rants to the aforementioned friends elicited a "Alas, 'tis so.". 57 | A bunch of :+1:s and :sweat-smile:s rapidly followed. These veteran Clojurists, 58 | each with over a decade of experience running Clojure in production, had 59 | felt that "full stack" burn too. Oh the schadenfreude. Woe be the newcomer 60 | professional programmer. Pity the hapless absolute beginner. 61 | 62 | As much as I dislike how confusing it has been, I tell myself it is a sign 63 | that the Clojure ecosystem is bigger and more diverse than most people believe. 64 | I am optimistic that much of the gallimaufry can be tamed with good curated 65 | documentation and tools, which people seem to be interested in (e.g the 66 | [[https://www.clojuriststogether.org/news/july-and-august-2023-long-term-project-updates/][recent Clojurists Together "long term funding" round]] heavily features 67 | documentation and tools authors). Hopefully this "ecosystem knowledge and 68 | tools" situation will improve in the coming years. 69 | 70 | What is not on that list is a Rails clone as a "killer app". The idea pops 71 | up regularly in this line of discussion. Personal tastes notwithstanding, 72 | I think frameworks are at odds with the emergent architecture of Clojureland 73 | itself, which derives from the fact that Clojure embraces functional composition 74 | /with/ à la carte polymorphism. The Expression Problem solved. Not objects, 75 | but also not pure functions alone. Both. Properties of both together engender 76 | dynamic networks with open-ended participation. 77 | 78 | If not one framework to rule them all, a cookbook of sorts could be a 79 | solution, but it would have to be a living document. Ecosystems change, 80 | and the Clojure ecosystem has been changing quite rapidly. Apparently, 81 | a capable, stable, backwards compatible language substrate is playground 82 | for fantastic creativity and innovation. Plus we also get access to host 83 | ecosystem creativity. That's a /lot/ of change to track! 84 | 85 | Which brings us back to the problem of mechanical knowledge graphs. 86 | 87 | Analogous to Clojure cli's core dependency graph resolver, a *mycelium-clj* 88 | will dynamically construct ecosystem pathways and graphs that you and I 89 | can traverse and query as human beings. 90 | - Start at (almost) nothing, and it will show you what's out there and 91 | reveal the interconnections. 92 | - It will source information from disparate sources and make them available 93 | in context. 94 | - It will let content writers and maintainers participate in the graph. 95 | - It could be a schema specification with globally namespaced structure, 96 | semantics, and open-ended interfaces. 97 | - Maybe it will integrate dependency graphs generated by dev tools. Maybe 98 | it will run basis "microformats" style machine-readable metadata. Maybe 99 | a shared ontology encoded using EDN (Garden of EDN, anyone?!), that 100 | authors can use to add metadata to their projects (books, blog posts, 101 | libraries etc.). 102 | 103 | An example *mycelium* session would address general questions like: 104 | 105 | - "I want to make a :full-stack :database backed :web application.". 106 | Starting from here it would take you down decision trees. Choose set of 107 | capabilities #{primary store, search, cache ..., unsure}, set of frontend 108 | or backend language choices #{clj, cljs, java, javascript, unsure}, set 109 | of transport formats #{json, edn, xml, avro, unsure}, set of build tools 110 | #{lein, cli-tools, npm, unsure}. Next, for each it would pull up library 111 | options, preferably with import instructions for the chosen build tool, 112 | link to the docs, and some quickstart summary. Finally, it would use the 113 | build tool to generate a skeleton project with the appropriate config 114 | files, directory structure, dependencies, editor hookups etc. 115 | 116 | As well as more specific questions like: 117 | 118 | - "I want to make a :full-stack :web-app with :postgres, :elasticsearch, 119 | :kafka, :clojure, :cljs, :re-frame, :cli-tools, :reitit, :edn, 120 | :clojure-test." would generate its own decision tree. 121 | 122 | As well as other fanciful stuff on those lines... 123 | 124 | A man can dream, no? 125 | 126 | #+caption: [[https://xkcd.com/2044/][xkcd 2044]]: "Sandboxing Cycle". 127 | #+caption: Or, the karmic wheel of unbundling and bundling. 128 | #+ATTR_HTML: :width 100% 129 | [[file:https://imgs.xkcd.com/comics/sandboxing_cycle.png]] 130 | 131 | --- 132 | 133 | /(Narrator: And with that he turned his gaze back to the abyss of his 134 | command line, where the crashed clj command remained crashed...)/ 135 | -------------------------------------------------------------------------------- /sources/posts/people-culture-values-strategy-technology/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: people > culture > values > strategy > technology 3 | #+summary: Technology is—and ought to be—the /byproduct/ of far more important, powerful, and deep-rooted aspects of organisations — including wholesale societies. The pandemic of technology-solutionism gleefully embraced and amplified by all and sundry makes me believe that people seem to have decided it's the other way around. 4 | #+author: Adi 5 | #+date: 2022-02-11 6 | #+updated: 2022-02-11 7 | #+tags: organisation_design systems culture 8 | #+include_toc: no 9 | # SHITE_META 10 | 11 | Here is a chain of causality that appeals to my sensibilities about the location of technology, in context of organisations. /"Technology solutionism"/ is the (apparently irressistible) urge to invert the chain of causality. 12 | 13 | The premise... 14 | 15 | ---> People create culture. 16 | 17 | ------> Culture shapes values. 18 | 19 | ---------> Values inform strategy. 20 | 21 | ------------> Technology is Strategy actualised. 22 | 23 | The implication... 24 | 25 | | Worst case | Best case | 26 | |----------------------------------------------------+-----------------------------------------------------| 27 | | > Destructive technology results | > Constructive technology results | 28 | | > from violent strategy | > from enlightened strategy | 29 | | > borne of pathological values | > borne of generative values | 30 | | > normalized by vile culture | > normalized by alive culture | 31 | | > catalysed by fear-based /leadership/ (verb-form) | > catalysed by trust-based /leadership/ (verb-form) | 32 | | > enabled by hapless bystanders | > co-created by highly engaged participants | 33 | | Unfortunately widespread, easily achieved. | Fortunately achievable, though high-effort. | 34 | | Hallmark of negative performance. | Hallmark of elite performance. | 35 | 36 | Wouldn't it be nice if the "Best case" happened most of the time? 37 | 38 | Wouldn't you like to be the sort of leader who makes it happen? A person of 39 | whom people genuinely say "/I did some of the best work of my life because of 40 | their leadership./"? Isn't that what good leadership is all about? 41 | 42 | I've had one or two of those in my life so far. Enough to /believe/. 43 | 44 | Here's the thing, though. 45 | - It requires a lot of /self/-work, but you can't go it alone. 46 | - There are no roads, but there are landmarks, GPSes, and gyroscopes. 47 | - There are no formulas, but there are stories, clues, and feedback loops. 48 | - There are few such leaders, but there are many followers, and leadership is 49 | teachable. Anyone going on this quest will discover the surprising array of 50 | people who want to rally around to help them succeed. I know I would! 51 | 52 | There are many places to look. Here's just one such bag full of some pretty 53 | good clues. 54 | - /Westrum's typology of organizational culture/ (table below), as [[https://cloud.google.com/architecture/devops/devops-culture-westrum-organizational-culture][presented here]] 55 | in context of Google's DORA research, but which is generally applicable to any 56 | team within any organisation, as well as to any org of any size in any industry. 57 | - Dr. Ron Westrum in conversation with Gene Kim at the /Idealcast/, for aural 58 | accompaniment during the day's perambulations: 59 | - Part 1: [[https://itrevolution.podbean.com/e/the-sociology-and-typologies-of-organizations-and-technical-maestros-with-dr-ron-westrum/][The Sociology and Typologies of Organizations, and Technical Maestros]] 60 | - Part 2: [[https://itrevolution.podbean.com/e/patterns-of-generative-cultures-how-they-can-be-destroyed-and-the-importance-of-trust-with-dr-ron-westrum/][Patterns of Generative Cultures: How They Can Be Destroyed and the Importance of Trust]] 61 | 62 | #+CAPTION: Table: *The Westrum organizational typology model: How organizations process information* (Source: Ron Westrum, "[[https://qualitysafety.bmj.com/content/13/suppl_2/ii22.short][A typology of organisation culture]])," /BMJ Quality & Safety 13, no. 2 (2004), doi:10.1136/qshc.2003.009522.)/ 63 | | Pathological | Bureaucratic | Generative | 64 | |-------------------------------+---------------------------+--------------------------| 65 | | Power oriented | Rule oriented | Performance oriented | 66 | | Low cooperation | Modest cooperation | High cooperation | 67 | | Messengers "shot" | Messengers neglected | Messengers trained | 68 | | Responsibilities shirked | Narrow responsibilities | Risks are shared | 69 | | Bridging discouraged | Bridging tolerated | Bridging encouraged | 70 | | Failure leads to scapegoating | Failure leads to justice | Failure leads to inquiry | 71 | | Novelty crushed | Novelty leads to problems | Novelty implemented | 72 | 73 | Happy generative acculturing! _\\// 74 | 75 | --- 76 | 77 | P.S. If you're on quest to build a generative software organization, and you wish 78 | you had some /eval/apply/ assistance, I will be delighted to play /Watson/ while 79 | you /Sherlock/. Email me at /sherlockseekingwatson (at) evalapply (dot) org/. 80 | -------------------------------------------------------------------------------- /sources/posts/reader-app-pandoc-bash/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Poor man's Reader App with Pandoc & Bash 3 | #+summary: Every so often, I want to avoid opening a website in a browser, for ... reasons. 4 | #+author: Adi 5 | #+date: 2022-02-10 6 | #+updated: 2022-02-10 7 | #+tags: functional_programming bash unix riff 8 | #+include_toc: no 9 | # SHITE_META 10 | /Throwback, June 27, 2020./ 11 | 12 | Every so often, I want to avoid opening a website in a browser, for ... reasons. 13 | 14 | Curl alone presents too much html. I want to try and read stuff. 15 | 16 | Today, I was playing with Igor Chubin's *awesome* terminal services (wttr.in, 17 | cht.sh etc.), and it hit me: 18 | 19 | "WAIT, there's pandoc, what if I just ... " 20 | 21 | #+hugo: more 22 | 23 | --- 24 | 25 | ... 26 | ... 27 | ... and an hour later... a terrible idea manifested itself. 28 | 29 | #+begin_src shell 30 | www_to_md() { 31 | pandoc --wrap=none -f html -t markdown "${1}" 32 | } 33 | 34 | drop_noise() { 35 | # remove pesky divs 36 | grep -v -E "(]?|*.>" | 37 | # squeeze multiple blank lines into one 38 | cat -s 39 | } 40 | 41 | cache_site() { 42 | local sitecache="${1:?'Fail. Path to create cache.'}" 43 | local mdfilename="${2:-'this.md'}" 44 | local evict_cache_qmark="${3:-no}" 45 | 46 | mkdir -p "${sitecache}" 47 | 48 | if [[ -f "${sitecache}/${mdfilename}" && "${evict_cache_qmark}" == "no" ]] 49 | then tee 50 | else tee "${sitecache}/${mdfilename}" 51 | fi 52 | } 53 | 54 | panwww() { 55 | local siteurl="${1}" 56 | local evict_cache_qmark="${2:-no}" 57 | local sitename="${siteurl/http*:\/\//www.}" 58 | local sitecache="/tmp/panwwwcache/${sitename}" 59 | local mdfilename="this.md" 60 | 61 | if [[ -f "${sitecache}/${mdfilename}" && "${evict_cache_qmark}" == "no" ]] 62 | then local cmd="cat ${sitecache}/${mdfilename}" 63 | else local cmd="www_to_md ${siteurl}" 64 | fi 65 | 66 | $cmd | drop_noise | cache_site "${sitecache}" "${mdfilename}" "${evict_cache_qmark}" 67 | } 68 | #+end_src 69 | 70 | so that ... 71 | 72 | #+begin_src shell 73 | panwww "https://www.recurse.com/" | less # fetches site the first time 74 | panwww "https://www.recurse.com/" | less # looks up "cache" 75 | panwww "https://www.recurse.com/" "refetch" | less 76 | #+end_src 77 | -------------------------------------------------------------------------------- /sources/posts/shell-aint-a-bad-place-to-fp-part-0-intro/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Shell ain't a bad place to FP: part 0/N: Introduction 3 | #+summary: Or, *Supremely Functional Bash Programming*, an exploration in N parts... 4 | #+author: Adi 5 | #+date: 2022-02-23 6 | #+updated: 2022-02-23 7 | #+tags: bash unix functional_programming architecture 8 | #+include_toc: yes 9 | # SHITE_META 10 | 11 | Once upon a time, while fiddling with a log processing shell pipeline, it hit me 12 | that the UNIX Way is a Surprisingly Functional Way, and so Functional Programming 13 | (FP) and Bash must be a natural fit. They fit. The world was never the same again. 14 | 15 | Now I believe it so much, that I will go on a limb and assert that it is 16 | highly inappropriate to write imperative-style Bash when we can just as easily 17 | write /supremely/ functional Bash. Why? Because it makes for supremely /better/ 18 | Bash (more reusable, more composable, more scalable, more enjoyable). 19 | 20 | Yes, I truly believe. 21 | 22 | Yes, I'm sane. 23 | 24 | No? Well OK, humour me... 25 | 26 | * Obligatory mea culpa 27 | Because I'm am going to lazy-stream this in N parts. Because my original post 28 | was growing to "never gonna ship" size. But /*not*/ because "Bash ain't a /real/ 29 | programming language". (Besides, in our post-reality world, we get to make 30 | our own reality.) 31 | ** Nothing here will be novel. 32 | - /*I've not invented anything that follows.*/ There are too many influences to 33 | enumerate fully. I'll provide references as I go along. 34 | - /*I expect to revise*/, correct, add to this series as I learn more over time. 35 | - /*Code in the post assumes Bash 4+*/, because that's what I've been using 36 | over the last 8-odd years. 37 | ** Your Mileage May Vary. 38 | - /*The Bash code will be both message and medium.*/ but I will describe 39 | general FP thinking, and Bash sure isn't the only medium. Please replicate 40 | solutions in your favourite language (in a UNIX-like way)! 41 | - /*I won't go crazy with Bash-isms*/, so the ideas and most of the code should 42 | generalise to most UNIXy shells. That said, I haven't used other shells to 43 | make equally confident claims about FP in them. 44 | ** FP suffuses my very being. 45 | - And I'm fairly confident the FP ideas will translate broadly, because I use 46 | them all the time; in my code (Clojure, APL, Ruby, JS, Python, SML...), in 47 | my designs for logging systems, infra-as-code systems, CI/CD systems, as 48 | well as designing human/communication workflows for teams. 49 | - But it's possible I've lived my life all wrong. 50 | * An outline of the "N" parts 51 | This (zeroth) post is about why the UNIX Way is the way of functional-style 52 | design [fn:1]. /~N~/ more posts are brewing, with examples and techniques. 53 | Likely one per topic: 54 | 55 | - A /rad/ example from 1986 to motivate the rest of the series. 56 | 57 | - Deep-dive into bash functions and function design techniques 58 | - Using functions to craft one's own Bytes-sized UNIX tools 59 | - Using them interactively like regular UNIX tools 60 | 61 | - Pipelining all the things 62 | - How we automatically get map / filter / reduce / early termination 63 | - Automatic streaming (regular pipes, tee, named pipes etc...) 64 | - Ways to do pipeline-friendly domain design, and to translate that into 65 | pipeline-friendly functions. 66 | 67 | - Avoiding manual state management with intelligent use of: 68 | - Variables, scopes, program invariants 69 | - Command substitution 70 | - Process substitution 71 | 72 | - Declarative programming 73 | - Templating with heredocs and herestrings 74 | - Trickshots with things like ~seq~, ~paste~ etc. 75 | - Reasonable uses of pattern matching 76 | 77 | - Environment isolation in detail 78 | - Lists and sub-shells 79 | - in Pipelines 80 | - Session portability 81 | 82 | - Designing idempotent / restart-friendly solutions 83 | - Because things can and will fail. 84 | 85 | - Maybe parallelism 86 | - Mainly because I haven't /had to/ [fn:2] write parallel Bash, but it will 87 | be fun to mess with. 88 | 89 | - Maybe sundry topics like associative arrays (Bash-only), job control, 90 | namespacing, metaprogramming, flame-bait like "pipes are monads" etc. 91 | * Prelude: Seeing the UNIX tools philosophy as a functional design philosophy 92 | The many remarkable aspects of UNIX Nature were discovered over half a century 93 | worth of versions, revisions, disasters, and reincarnations. While many avatars 94 | of UNICES and UNIX-likes have come and gone, the UNIX Way (articulated by the 95 | 1990s) has thrived through the ravages of time. Here it is, embodied in the 96 | form of the UNIX Tools Philosophy. 97 | 98 | - /*Most importantly, do one thing*/, and do it well (just like a function). 99 | 100 | - Consume and emit /*plain data*/ (just like a function). 101 | 102 | - /*Output the same data format as is received at input*/ (formerly only plain 103 | lines of text, but now also structured literal data like JSON, EDN etc.) 104 | 105 | - /*Don't be chatty*/ (i.e. avoid side-effects, again, just like a function). 106 | 107 | - Be line-oriented, which design choice turns out to be /*naturally streaming*/, 108 | with /*automatic support for map/filter/reduce*/, which we will use a lot. 109 | 110 | - Favour /*universal composition*/ via standard interfaces like file descriptors, 111 | standard IN/OUT/ERROR, line-orientation, and UNIX pipes (quite monadic, an 112 | argument for much later). 113 | 114 | - Be as /*general-purpose*/ as possible for wide reusability, in any context. 115 | This pushes tools away from imposing internal structure on input data, as 116 | also from maintaining persistent or shared internal state. 117 | 118 | - Ideally have sane behaviour like environment isolation, idempotence, etc. 119 | 120 | - Last but not least, when out-of-the-box solutions are not good enough, it 121 | encourages us to detour to building our own tools. And these can be simple 122 | Bash functions, usable interactively at the command line, just like full 123 | standalone programs! 124 | 125 | Of course, practice can diverge from the ideal, but not by too much (many tools 126 | have to work with stateful objects like files and sockets, some may rely on 127 | lock-files, some should be idempotent but aren't, others may grow to do more 128 | than one thing and do everything badly etc.). Besides, not even Haskellers 129 | escape this reality, so there. 130 | 131 | It stands that the UNIX Way strongly encourages us to create laser-focused, 132 | composable, purely functional, data-flow oriented programs that we can remix 133 | at will into surprisingly powerful solutions with surprisingly little ceremony. 134 | 135 | This /Way/ has proven to be very useful at scales several orders of magnitude 136 | apart; from in-program 1-liner functions, to 1 kilobyte tools, to operating 137 | systems, to planet-wide distributed systems. This unreasonable effectiveness 138 | is why UNIX People have long valued these values. 139 | * "Screw that, show me your code" 140 | Sorry! I feel ya... no code, no dice. Here is some of my FP-style Bash. 141 | I plan to crib liberally from these to illustrate the posts-to-come. 142 | 143 | - *[[https://github.com/adityaathalye/bash-toolkit][bash-toolkit]]*: 144 | a "Swiss Army Toolkit" of functions I've been accumulating over the years. 145 | 146 | - *[[https://github.com/adityaathalye/oxo][oxo]]*: 147 | a retro-style noughts and crosses game in Bash (and it speaks!). 148 | 149 | - Next up: *[[https://evalapply.org/posts/shell-aint-a-bad-place-to-fp-part-1-doug-mcilroys-pipeline/][Shell ain't a bad place to FP: part 1/N]]* 150 | in which we take apart Douglas McIlroy's famous pipeline from 1986, to 151 | motivate the rest of the series. "Take apart" in the sense of "Design is 152 | about taking things apart.". A most respectful sense. 153 | 154 | May the Source be with us. 155 | 156 | [fn:1] Recently I went on for a bit in general about 157 | [[https://www.evalapply.org/posts/what-makes-functional-programming-systems-functional/][what does it even mean to be "functional"?]] 158 | Read that if it pleases you, because it informs my approach to /Supremely Functional/ 159 | Bash programming. 160 | 161 | [fn:2] There was the one time I could have, at a $DAYJOB, but I was quite green, 162 | and had deadline, and it was a one time log analysis thing, and I a large EC2 163 | box to waste, which I hogged for half a day, and came away stunned that my crappy 164 | shell pipeline chewed through ~600 GiB (gzipped) without crashing anything. 165 | -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/demo-2/about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | A Shtatic Shite 8 | 9 | 10 | 11 | 12 | 51 | 52 | 53 | 62 |
63 |

About

64 |
65 |

Who did this?

66 |
67 | 68 | Yes I did. Briefly, I am... 69 | 70 |

A stranger on the Internet.

71 |

Tilting at windmills...

72 |

With a dark past fully detailed in this resume.

73 | 77 |
78 |
79 |
80 |

Why are you here?

81 |
82 | 83 | In which I help you understand the life choices that... 84 | 85 |

... brought you here.

86 |

And perhaps explain the raison d'etre of this site.

87 |

Much existential angst follows...

88 | 92 |
93 |
94 |
95 |

Colophon

96 |
97 | 98 | How this site was made... 99 | 100 |

With system fonts.

101 |

With simple colours.

102 |

With lots of HTML.energy

103 | 107 |
108 |
109 |
110 |
111 |
112 |

Copyright, Yours Truly.

113 |

All content is MIT licensed, except where specified otherwise.

114 |
115 | 116 | 117 | -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/demo-2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | A Shtatic Shite 8 | 9 | 10 | 11 | 12 | 51 | 52 | 53 | 62 |
63 |

Blog posts

64 |
65 |

Hello, world.

66 |
67 | 68 | In which we greet the world. 69 | 70 |

Hello, world.

71 |

I'm here.

72 |

And I'm going to take you head-on...

73 | 77 |
78 |
79 |
80 |

Wtf, world?!

81 |
82 | 83 | In which we marvel at the various insanties of life and the living. 84 | 85 |

Wtf, world.

86 |

I'm here.

87 |

And I'm just... How do you even work?

88 | 92 |
93 |
94 |
95 |

Goodybe, world.

96 |
97 | 98 | In which we bid adieu to the world. 99 | 100 |

Goodbye, world.

101 |

It was nice being here.

102 |

I hope we meet again...

103 | 107 |
108 |
109 |
110 |
111 |
112 |

Copyright, Yours Truly.

113 |

All content is MIT licensed, except where specified otherwise.

114 |
115 | 116 | 117 | -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/demo-2/resume.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | A Shtatic Shite 8 | 9 | 10 | 11 | 12 | 51 | 52 | 53 | 62 |
63 |

Resume

64 |
65 |

Job 3 title, Company, From - To

66 |
67 | 68 | Summary of things I did here. 69 | 70 |

+ An achievement

71 |

+ A contribution

72 |

+ A lesson learned

73 | 77 |
78 |
79 |
80 |

Job 2 title, Company, From - To

81 |
82 | 83 | Summary of things I did here. 84 | 85 |

+ An achievement

86 |

+ A contribution

87 |

+ A lesson learned

88 | 92 |
93 |
94 |
95 |

Job 1 title, Company, From - To

96 |
97 | 98 | Summary of things I did here. 99 | 100 |

+ An achievement

101 |

+ A contribution

102 |

+ A lesson learned

103 | 107 |
108 |
109 |
110 |
111 |
112 |

Copyright, Yours Truly.

113 |

All content is MIT licensed, except where specified otherwise.

114 |
115 | 116 | 117 | -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | A Shtatic Shite 8 | 9 | 10 | 11 | 12 | 40 | 41 | 42 | 51 |
52 |

Blog posts

53 |
54 |

Hello, world.

55 |
56 | 57 | In which we greet the world. 58 | 59 |

Hello, world.

60 |

I'm here.

61 |

And I'm going to take you head-on...

62 | 66 |
67 |
68 |
69 |

Wtf, world?!

70 |
71 | 72 | In which we marvel at the various insanties of life and the living. 73 | 74 |

Wtf, world.

75 |

I'm here.

76 |

And I'm just... How do you even work?

77 | 81 |
82 |
83 |
84 |

Goodybe, world.

85 |
86 | 87 | In which we bid adieu to the world. 88 | 89 |

Goodbye, world.

90 |

It was nice being here.

91 |

I hope we meet again...

92 | 96 |
97 |
98 |
99 |
100 |
101 |

Copyright, Yours Truly.

102 |

All content is MIT licensed, except where specified otherwise.

103 |
104 | 105 | 106 | -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/morpheus-red-blue-pill.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/shite-the-static-sites-from-shell-part-1/morpheus-red-blue-pill.jpg -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/plain-static-website-cthulahoops-view-source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/shite-the-static-sites-from-shell-part-1/plain-static-website-cthulahoops-view-source.png -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/plain-static-website-cthulahoops.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/shite-the-static-sites-from-shell-part-1/plain-static-website-cthulahoops.png -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/shite-demo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/shite-the-static-sites-from-shell-part-1/shite-demo-1.png -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/shite-demo-2-about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/shite-the-static-sites-from-shell-part-1/shite-demo-2-about.png -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/shite-demo-2-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/shite-the-static-sites-from-shell-part-1/shite-demo-2-index.png -------------------------------------------------------------------------------- /sources/posts/shite-the-static-sites-from-shell-part-1/shite-demo-2-resume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/shite-the-static-sites-from-shell-part-1/shite-demo-2-resume.png -------------------------------------------------------------------------------- /sources/posts/software-debt/STELLAReportFinalFinal_Coping_With_Complexity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/software-debt/STELLAReportFinalFinal_Coping_With_Complexity.png -------------------------------------------------------------------------------- /sources/posts/software-debt/clojure-codebase-introduction-retention-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/posts/software-debt/clojure-codebase-introduction-retention-code.png -------------------------------------------------------------------------------- /sources/posts/software-demos/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Software demos as deliberate acts of serious play 3 | #+summary: Making a software demo is a form of deliberate, serious play. An act that feeds our curiosity, inventiveness, and drive. It enlivens. It enriches. It entertains. And as we asymptotically approach the A.G.I. that's just around the corner, the capacity for deliberate, serious play will remain distinctively, deeply, deliciously human. Career software people like yours truly may please take note! 4 | #+author: Adi 5 | #+date: 2023-06-04 6 | #+updated: 2023-06-04 7 | #+tags: programming culture whyto software_design meta 8 | #+include_toc: yes 9 | # SHITE_META 10 | 11 | * Best Software Demo! 12 | To me, the best kind of /software demo/ is any program created in the inventive, 13 | artistic, seriously playful, playfully serious sense of /demoscene/ [fn:1], 14 | /and/ the freely shareable sense of /demoware/ [fn:2]. 15 | 16 | Dylan Beattie's brilliant talk, /[[https://dylanbeattie.net/talks/the-art-of-code.html][The Art of Code]]/, is my all time favourite 17 | example of this sense of /demo/. 18 | 19 | #+begin_export html 20 |
21 |
The Art of Code — Dylan Beattie
22 | 23 |
24 |

25 | Software and technology have changed every aspect of the world we live in. 26 | At one extreme are the ‘mission critical’ applications - the code that 27 | runs our banks, our hospitals, our airports and phone networks. Then 28 | there’s the code we all use every day to browse the web, watch movies, 29 | create spreadsheets… not quite so critical, but still code that solves 30 | problems and delivers services. 31 |

32 |

33 | But what about the code that only exists because somebody wanted to write 34 | it? Code created just to make people smile, laugh, maybe even dance? Maybe 35 | even code that does nothing at all? Code that was created just to see if 36 | it was possible? 37 |

38 |
39 |
40 | #+end_export 41 | 42 | Many venues exist featuring such software demos. My favourite public examples 43 | include [[https://bangbangcon.com/][!!Con]], [[https://handmade-seattle.com/][Handmade Seattle]], [[https://sigbovik.org/][Sigbovik]], the [[https://joy.recurse.com/][Recurse Center]]. 44 | Your local meetup is a great place to make a little demoscene of your own. 45 | 46 | * Y U NO DEMO???? 47 | Like you and I, so many of us career software people first turned to computers 48 | for the sheer creativity of the medium. Endless tinkering. Instant feedback 49 | (gratifying or annoying). Serendipitous side quests. Deep wabbit holes of 50 | bugs-hunting. All the time learning, sharing, staying up all night arguing with 51 | strangers on the Internet. Sometimes even taking their advice. We were /playing/. 52 | 53 | Then, at some point, we went to work on other peoples' software. And after some 54 | more points we perhaps set out to make our own software or, heaven forefend, our 55 | own software business. And then one fine day, dramatically, we caught ourselves 56 | past yet another point, whizzing down the thermocline of drudgery into the cold 57 | depths of despair, intoning... 58 | 59 | #+begin_quote 60 | "WTF; where did the fun go?!" 61 | 62 | --- You, asking the mirror. 63 | #+end_quote 64 | 65 | Yours truly is with you, having managed to brown-out of a software job or two, 66 | and burnout of a software company I tried to help start. The latter fact is even 67 | chronicled in a book which shall remain safely ensconced in nameless obscurity 68 | because nobody needs to re-visit two years of anxiety, insomnia, and the insanity 69 | of 100 hour work weeks, character-building though that life was. 70 | 71 | But wait! Lest the invisible hand that feeds feels embittened... 72 | 73 | * You make. I make. 74 | 75 | I hereby proclaim that I /love/ the rush of making, shipping, scaling product 76 | (and production)! 77 | 78 | Truly, I do. 79 | 80 | All I am saying is, I /also/ know something of the sharp edges that cut. The 81 | dark places one goes to when it all gets too much. Ben Horowitz's line is 82 | hilarious and relatable. 83 | #+begin_quote 84 | “As a startup CEO, I slept like a baby. I woke up every 2 hours and cried.” 85 | 86 | --- Ben Horowitz 87 | #+end_quote 88 | 89 | Except... 90 | 91 | As celebrated as the mythic /Great Man/ might be, the gauntlet of weathering 92 | /The Struggle/ isn't thrown only to /His/ Lonesome Greatness, is it? I believe 93 | anyone who chooses /The Struggle/ of trying to make /something/ from nothing is 94 | playing the high stakes game in their own ways. /They/ too shoulder their share 95 | of the burden of navigating unknown unknowns, existential risks, and the 96 | ever-present specter of abject failure. 97 | 98 | And all this time they though all they did was wade through subtly broken and 99 | misleadingly stale software manuals, fix yet another broken dependency, make 100 | tickets, move tickets, say yes to way too many meetings (for why?), mock A.I., 101 | fear A.I., use A.I., fear A.I... uh, and other work things. 102 | 103 | And they're not certainly wrong. But they're also not certainly right. For as 104 | much as it is a /"No, but"/ world, intent on smacking your head every time you 105 | think /"hey, what if I just..."/, it is also a /"Yes, and"/ world capable of 106 | saying /"sure, why not?"/. 107 | 108 | All they need to do is inject themselves with a self-prompt. A little red pill. 109 | 110 | #+begin_quote 111 | Aren't I a maker in my own right? 112 | #+end_quote 113 | 114 | Yes, I are. 115 | 116 | And, demos are how I own it [fn:3]. 117 | 118 | Hence I demo. 119 | 120 | Hence. You. Demo! [fn:4] 121 | 122 | * To: Serious Business. Cc: All. 123 | 124 | /*Sub: Out with the CTO's Office, in with the CTO's Demoscene!*/ 125 | 126 | Seriously. 127 | 128 | Yes the prospect of demo-derived joy will please many, but it's not just 129 | personal, it's business too. Here are some Important Business Reasons for, shall 130 | we say, demo driven business development... 131 | 132 | - /Demos cause progress/ by turning abstractions into tangibles. Shipping 133 | output is a powerful catalyst. 134 | - /Demos rally stakeholders/ around vision and goals. A sharp demo can speak 135 | louder than a thousand meetings. 136 | - /Demos foster psychological safety/ to experiment, transcend set mindsets, 137 | and remove creative blocks. 138 | - /Demos reduce risk/ of sunk costs locking us into bad choices, by virtue 139 | of being intentionally impermanent. 140 | - /Demos educate entertainingly./ We are not machines. Fun and joy are at least 141 | as essential to making creative connections, as the struggle of surmounting the 142 | energy gradient of forming new knowledge. 143 | - /Demos fuel camaraderie/ through shared experiences of making, failing, 144 | showing (and showing off!) little and big cool /warez/. 145 | - /Demos sell product/ by making our product relatable to customers in their 146 | unique contexts. 147 | 148 | And last but not least... 149 | 150 | - /A truly great demo is indistinguishable from magic./ After it occurs, the 151 | impossible becomes possible. A clear boundary separates past and future. Life 152 | changes forever. This is the realm of genius and wizardry. 153 | 154 | /"Ah, 20% time! Culture hack!"/, you say. 155 | 156 | I say /"psych!"/. 157 | 158 | In theory, culture hacks work in practice. What works is the intangible /that/. 159 | That which fosters a pervasive culture of serious play. That which makes those 160 | of us in the business of software—indies, teams, companies—get very good indeed 161 | at what we do. 162 | 163 | You see you can't /make/ your /demos/ love The Demo. 164 | 165 | But you can certainly show the way. 166 | 167 | One way is to walk the way. 168 | 169 | * So demo that demo already 170 | Maybe you want to lead by example. Or maybe you want to rethink your [[https://www.evalapply.org/now][own]] 171 | entire life as a software maker (among other things). /The Way of the Demo/ may 172 | be just what the doctor ordered. 173 | 174 | [[./index.html#best-software-demo][Beattie]] brilliantly illuminates for us career software people that it is not 175 | strange to experience respite and recovery from the business of serious software, 176 | in the guise of even more software; seriously playful software. 177 | 178 | So venture thither! Make fun-for-you software demos, while you await the day 179 | when your hip new LLM friends finally learn how to alliterate wryly, cleverly, 180 | spontaneously while they demoscene their cool demos while also running your 181 | company or your life to runaway success. 182 | 183 | That'll be the day. 184 | 185 | ;) 186 | 187 | * Footnotes 188 | 189 | [fn:1] https://en.wikipedia.org/wiki/Demoscene 190 | #+begin_quote 191 | The demoscene is an international computer art subculture focused on producing 192 | demos: self-contained, sometimes extremely small, computer programs that produce 193 | audiovisual presentations. The purpose of a demo is to show off programming, 194 | visual art, and musical skills. Demos and other demoscene productions (graphics, 195 | music, videos, games) are shared at festivals known as demoparties, voted on by 196 | those who attend and released online. 197 | #+end_quote 198 | 199 | [fn:2] However, the other notion of demoware as /intentionally crippled/ software 200 | is... yuck. 201 | #+begin_quote 202 | *Demoware*: Software that is used to demonstrate a product's features, but has limitations. 203 | It will either expire at a set time, or it is limited in functionality. See 204 | trialware, crippleware, lite version, shareware and wares. 205 | 206 | --- [[https://www.pcmag.com/encyclopedia/term/demoware][pcmag.com]] 207 | #+end_quote 208 | Deliberate crippling is very different from making it deliberately small (e.g. 209 | Unix tools), which is a forward-looking creative constraint. I will argue that 210 | even WordPress, because of its pluggable architecture, is "deliberately small". 211 | The permutations of WP + pluggable code, in the WP universe, absolutely dwarf the 212 | core CMS. That kind of a design choice liberates creativity, which crippleware 213 | forefends /by design/. Ick. For similar reasons, /lite version/ (even open core) 214 | is an ethical minefield. One could start off well-intentioned, but when the 215 | quartely earnings come a-callin' it gets very hard to remain generous about 216 | foundational promises like "free forever" or "10,000 messages searchable". 217 | Trialware is also OK in my book, provided one gets to use the whole thing for a 218 | reasonable period, with no data lock-in, enough to make up one's mind about 219 | burdening the exchequer. 220 | 221 | [fn:3] I'm /that guy/ who insists on making all his [[https://github.com/adityaathalye/slideware][conference talks]] 222 | live demos. Dangerous? Who's that? 223 | 224 | [fn:4] Hey, maybe get the A.I. do the meeting instead of you? And the 225 | meeting notes. And schedule the follow up meeting? And... Well, I don't know 226 | what will make you nerd out. I get kicked about things like this... 227 | - How far can I go only with Bash? 228 | - Suppose I implemented in $Language? 229 | - This technique / trick / pattern is amazing! Here's why and how to use it! 230 | - /"Ooooh, what does this button do?"/ (a thought that emerges when inside the 231 | guts of some library or database manual or profiler feature set). 232 | - What if we were forbidden the use of a database for X? 233 | -------------------------------------------------------------------------------- /sources/posts/tools-for-thought/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Riff: Classifying Tools for Thought 3 | #+summary: Trying out a classification for "Tools for Thought" as a means of augmenting the human intellect, hot on the heels of recent community conversations about ChatGPT, CoPilot, Stable Diffusion etc... 4 | #+author: Adi 5 | #+date: 2023-01-19 6 | #+updated: 2023-01-19 7 | #+tags: meta riff intelligence_augmentation tools_for_thought 8 | #+include_toc: no 9 | # SHITE_META 10 | 11 | At the risk of badly mangling things smarter people have probably already worked 12 | out [fn:1] over seven plus decades and counting of the ongoing computer revolution [fn:2], 13 | here goes. 14 | 15 | * Category One: Memory Assistant 16 | 17 | I'd box all the note taking tools in here---as persistent store and/or organiser 18 | and/or search tools. As a user of such a tool, all meaning-making is the job of my 19 | brain. I must work out the known unknowns, deal with the unknown unknowns when 20 | they happen etc. 21 | 22 | The tool functions like a mechanical memory + ontology + topology assist, which 23 | helps me do a lot of thinking + learning /over long periods of time/ (like days, 24 | weeks, years). Things like Ken Iverson's concept of /Notation as a Tool of Thought/ [fn:3] 25 | would also fall into this category (filed under "methods to compress information 26 | into symbols and mnemonics and transmit them"). 27 | 28 | Hell, why be so fancy? I dump it all into my haphazardly organised org files and 29 | ~rgrep~ and its going... fine? 30 | 31 | 🤷‍♂️ 32 | 33 | * Category Two: Co-processor 34 | 35 | Two intellects working together to arrive at a common model / picture / frame of 36 | understanding. People on the Internet and in my familiar circle of gentlenerds 37 | seem to be excited about CoPilot / ChatGPT etc. in this sense. 38 | 39 | I can't help but see those as just more of /Category One/ type tools. Why? 40 | Because co-processors must be capable of communicating understanding of abstract 41 | models with each other (a kind of "Communicating with Aliens" [fn:4] problem). 42 | AFAIK, none of these tools are capable of explaining /why/ they're doing what 43 | they're doing. 44 | 45 | The one exception I could concede to is machines that are excellent at /finite 46 | games/. That too because odds are higher of being able to independently verify 47 | the machine's meta descriptions, and the outcomes would be reasonably reproducible 48 | (viz. "I did X, because of heuristic Y, and rules P, Q, R."). 49 | 50 | * Category Three: Teacher 51 | 52 | One intelligence absorbing greater truths discovered by (or previously absorbed 53 | by) another intelligence. Where the other intelligence has the metacognition to 54 | know what they know, and to direct the other intelligence to that level of 55 | understanding. The magic of beings capable of transferring culture, stories, 56 | Laplace transforms, rate reaction equations, rules of grammar, interpretation of 57 | law etc. across minds, and generations. 58 | 59 | I'm thinking tribes, coaches, mathematics circles, therapists, the Vulcan Science 60 | Academy and so forth... the ability to conjure up and communicate /about/ concepts 61 | like communicating with aliens. 62 | 63 | AFAIK, only biology is capable of producing this category of tools of thought. 64 | 65 | In this context, I'm fascinated by the work being done on Bioelectric Networks 66 | by Michael Levin's group [fn:5]. Almost prosaically, in their work/world the 67 | definition of intelligence is a /mechanical/ one. So much so that they are able 68 | to model and then produce (though not control or guarantee) biological structures 69 | capable of progressively more sophisticated kinds of intelligence in the mechanical 70 | terms they describe. 71 | 72 | Which makes me wonder... 73 | 74 | Is there something like the Kardashev Scale [fn:6], but for levels/depths/spans 75 | of Intelligence? 76 | * Footnotes 77 | 78 | [fn:1] These two links capture the overarching context, discovered thanks to 79 | that fine Gentleman and Scholar, [[http://fogus.me/me/][fogus]]. 80 | 81 | [[https://www.iosrjen.org/Papers/Conf.19021-2019/Volume-5/6.%2030-33.pdf][Overview of Intelligence Amplification]]. 82 | /Intelligence amplification/ (IA) refers to the effective use of Information 83 | technology in augmenting human intelligence. 84 | 85 | /[[http://www.rheingold.com/texts/tft/][Tools for Thought]]/; 86 | an "an exercise in retrospective futurism" by Howard Rheingold, who introduced 87 | the idea as follows. 88 | #+begin_quote 89 | *Tools for Thought* is an exercise in retrospective futurism; that is, I wrote it 90 | in the early 1980s, attempting to look at what the mid 1990s would be like. My 91 | odyssey started when I discovered Xerox PARC and Doug Engelbart and realized that 92 | all the journalists who had descended upon Silicon Valley were missing the real 93 | story. Yes, the tales of teenagers inventing new industries in their garages were 94 | good stories. But the idea of the personal computer did not spring full-blown 95 | from the mind of Steve Jobs. Indeed, the idea that people could use computers to 96 | amplify thought and communication, as tools for intellectual work and social 97 | activity, was not an invention of the mainstream computer industry nor orthodox 98 | computer science, nor even homebrew computerists. If it wasn't for people like 99 | J.C.R. Licklider, Doug Engelbart, Bob Taylor, Alan Kay, it wouldn't have happened. 100 | But their work was rooted in older, equally eccentric, equally visionary, work, 101 | so I went back to piece together how Boole and Babbage and Turing and von Neumann 102 | — especially von Neumann — created the foundations that the later toolbuilders 103 | stood upon to create the future we live in today. You can't understand where 104 | mind-amplifying technology is going unless you understand where it came from. 105 | #+end_quote 106 | 107 | [fn:2] [[http://www.vpri.org/pdf/m2007007a_revolution.pdf][The Real Computer Revolution Hasn't Happened Yet]] — Alan Kay, 108 | Viewpoints Research Institute. See also, [[https://www.youtube.com/watch?v=oKg1hTOQXoY][video]] of 109 | the talk he delivered at OOPSLA, in 1997. 110 | 111 | [fn:3] [[https://www.jsoftware.com/papers/tot.htm][Notation as a Tool of Thought]], by Ken Iverson. 112 | #+begin_quote 113 | The thesis of the present paper is that the advantages of executability and 114 | universality found in programming languages can be effectively combined, in a 115 | single coherent language, with the advantages offered by mathematical notation. 116 | #+end_quote 117 | 118 | [fn:4] The notion that fell out of JCR Licklider's thinking on how might we make 119 | an "[[https://en.wikipedia.org/wiki/Intergalactic_Computer_Network][Intergalactic Computer Network]]". 120 | 121 | #+begin_quote 122 | Consider the situation in which several different centers are netted together, 123 | each center being highly individualistic and having its own special language and 124 | its own special way of doing things. Is it not desirable, or even necessary for 125 | all the centers to agree upon some language or, at least, upon some conventions 126 | for asking such questions as “What language do you speak?” At this extreme, the 127 | problem is essentially the one discussed by science fiction writers: “how do you 128 | get communications started among totally uncorrelated “sapient” beings?” 129 | #+end_quote 130 | 131 | [fn:5] Check out /[[https://as.tufts.edu/biology/levin-lab][The Levin Lab]]/ at Tufts University, for some brain-melting science. 132 | #+begin_quote 133 | We work at the intersection of developmental biology, computer science, and cognitive 134 | science. Our goal is to understand degrees of intelligence at multiple scales of 135 | biological, artificial, and hybrid systems; we use these insights to develop 136 | interventions in regenerative medicine. 137 | #+end_quote 138 | 139 | [fn:6] The [[https://en.wikipedia.org/wiki/Kardashev_scale][Kardashev Scale]] /"is a method of measuring a civilization's level of 140 | technological advancement based on the amount of energy it is able to use. The/ 141 | /measure was proposed by Soviet astronomer Nikolai Kardashev in 1964."/ 142 | 143 | Michael Levin's group proposes this tantalizing [[https://aeon.co/essays/how-evolution-hacked-its-way-to-intelligence-from-the-bottom-up][modular model of cognition]]. 144 | #+begin_quote 145 | Intelligence is not something that happened at the tail end of evolution, but 146 | was discovered towards the beginning, long before brains came on the scene. 147 | #+end_quote 148 | -------------------------------------------------------------------------------- /sources/posts/what-have-you-been-curious-about/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: What have you been curious about? 3 | #+summary: Arguably a more interesting, revealing, and kinder question than "What are you curious about?" 4 | #+author: Adi 5 | #+date: 2023-06-21 6 | #+updated: 2023-06-21 7 | #+tags: meta riff 8 | #+include_toc: no 9 | # SHITE_META 10 | 11 | If you are anything like me, you will have about five answers at any given point 12 | in time for "What /are/ you curious about?". And that set will change depending 13 | on the day of the week. Or, also like me, you may be having that sort of week 14 | where you (mistakenly) "know for sure, beyond a shadow of doubt" that you have 15 | lost the curiosity directive. Basically, you might immediately (and once again, 16 | mistakenly) feel like a flake or a failure or some horrid in-between. I sure do. 17 | 18 | Luckily, arguably, a more interesting, revealing, and kinder question is; 19 | "What /have you been/ curious about?". 20 | 21 | You see as it happens, days glom into weeks, weeks into months and maybe even 22 | years. Only in hindsight do I discover that I /have been/ non-casually curious 23 | about "X". That my mind kept returning to that "X". That it drove me to action 24 | in some way; a blog post written, a book read, a long discussion had, a life 25 | experiment attempted, a tutorial followed, a behaviour tried, an experience opted 26 | into etc. 27 | 28 | For me the last year-plus became about examining the contents of my mind, 29 | identifying observing and acknowledging personal traits and oddities, making the 30 | self do things that past-me would scoff at or shy away from or fear, articulating 31 | what I want my professional life to be, and so forth. 32 | 33 | I can tell that this has been the "curiosity drive" that I was so convinced I had 34 | lost permanently, because I recently created a [[https://www.evalapply.org/now]["now" page]] that 35 | publicly reflects some of that, and ended up writing [[https://www.evalapply.org/posts/software-demos/][this blog post]] about what I 36 | want to do for fun and money(!) and ended up applying for a second batch at the 37 | [[https://www.recurse.com/][Recurse Center]] (starting soon!). 38 | 39 | That sounded like heavy work, but I have honest-to-goodness been /playing/ in the 40 | sense of /serious play/. Among other things, I have re-framed /"adult"/ as /"still 41 | an impish, wide-eyed, curious thirteen year old underneath sediments and crusty/ 42 | /layers of accreted life experiences and beliefs and rules and... just *stuff*"/. 43 | 44 | And I feel a looking-back-to-curiosity exercise has power to shed light on where 45 | to look ahead (and why to do it). More so, I feel it has power to grant permission 46 | to that "insatiably curious thirteen year old self" to step out and /play/. 47 | Because it probably already has been up to something, while your attention was 48 | elsewhere. 49 | 50 | So, here is a prompt (see what I just did there? ;-)) ... 51 | 52 | */What /have you been/ curious about?/* 53 | 54 | LLAP _\\// 55 | 56 | (NB: This is a lightly edited version of my newsletter that went out today.) 57 | -------------------------------------------------------------------------------- /sources/posts/what-makes-functional-programming-systems-functional/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: What makes Functional Programs and Systems "Functional"? 3 | #+summary: In which we ponder the Functional Nature of Life, The Universe, and Everything. Please feel free to follow through the weeds, or jump straight to the bottom for my 2 nano BTC on the matter. (Or my current state of mind, at any rate.) 4 | #+author: Adi 5 | #+date: 2022-02-22 6 | #+updated: 2022-02-22 7 | #+tags: meta functional_programming architecture systems 8 | #+include_toc: yes 9 | # SHITE_META 10 | 11 | Disclaimer: I live in the Land of Lisp, meditate in the Church of Alonzo, and am ever-wary of The State. Only converts /might/ find some entertainment value. 12 | 13 | #+begin_quote 14 | /"For the love of State is the root of all evil: which while some coveted after,/ 15 | /they have erred from Lambda the Ultimate, and pierced themselves through with/ 16 | /many sorrows."/ 17 | 18 | --- self. 19 | #+end_quote 20 | 21 | * Is it already suffusing your very being? 22 | Because so-called "Functional Programming" started becoming pretty sexy over 23 | the 2010s. By the 2020s, it started infiltrating all the things, small and big 24 | and hyperscaled. 25 | 26 | Now you can't get people to shut up about their declarative infrastructure-as-code 27 | as-YAML microservices-first infinitely elastic shared-nothing event-sourced 28 | map-reducing lambda architecture marvels. 29 | 30 | Now your VCs and your board nod sagely when these words flash past in your slick 31 | OKR plan vision strategy slide decks. Now they further /"Hey, quick question"/ 32 | you to same-page on your strategy for blockchain and smart contracts. And 33 | general web3 readiness. So does every novice hire it seems, no matter their role. 34 | 35 | Now---and be honest, OK?---don't you feel like everybody should just mentally 36 | lie down for a few minutes in their metaverse, pass around the meta-ayahuasca, 37 | and after the purge just ask simple meta-questions about FP and life for a 38 | change? Because, for the love of lambda, we haven't even gotten a breather 39 | from the fast-nearing AI supremacy? 40 | 41 | No? OK, consider the following incomplete list of traits commonly attributed 42 | to the "Functional" paradigm of programming languages and of systems. Alongside, 43 | consider: 44 | 45 | - Which traits does your pet programming language (or system) provide by default? 46 | - Which traits do you create yourself in your programs (and systems)? 47 | - Which traits draw the hard line between "Functional" and other kinds of 48 | programs (and systems)? 49 | - Which traits /really/ matter? 50 | - Why would you even want any of it in the first place? 51 | 52 | And will we really achieve world domination with FP? (Yes, we will.) 53 | * Is it Mathematics? 54 | Is it about writing "pure" functions? 55 | 56 | This is a bit of a tautology. A function is "pure" by definition. It specifies 57 | a fixed mapping of an input domain to an output domain. When invoked, it 58 | changes nothing about the state of the world. Which begs the question, how can 59 | a thing that /does/ nothing be computationally useful? (Spoiler: it isn't in 60 | isolation, unless of course, you figure out a way to use the computational 61 | uselessness to turn staggeringly larger amounts of electricity into progressively 62 | smaller fragments of your imagination, on a blockchain somewhere). But I digress... 63 | 64 | Must we further also have "first-class" functions? 65 | 66 | Ones that we can pass around as values? This lets us describe all manner of 67 | deferred computations, including un-computable absurdities like infinite sequences, 68 | and partial applications that will sit around forever if we don't complete them. 69 | 70 | And do we absolutely /need/ the solid ground of Lambda Calculus or Category 71 | Theory to /pre-exist/? 72 | 73 | That's an easy one to refute, but these things have become rather holy grail-y 74 | now. If you don't know your monad laws, I'm sorry you're not permitted near 75 | functions any more. Oh, and what about proofs? These are in the process of 76 | holy-grailing too... 77 | * Is it being "declarative"? 78 | Reduce/ravel/plan/derive/goal-seek? 79 | 80 | To be "declarative" is to want to write down a set of constraints or rules 81 | or input-output relationships, and leave it to the system to figure out not 82 | only /what operations/ to perform, but also /how/ and /when/ to perform them. 83 | 84 | The declarative world is thrice-removed from the "procedural" world, where we 85 | have to tell the computer the what, how, and when in excruciating detail. 86 | 87 | SQL, Prolog, APL are seen as "highly declarative" languages. CSS is also a 88 | highly declarative language (which, I feel, is why people have a really hard 89 | time with it---CSS is a /constraint mechanism/ but our minds are strongly 90 | conditioned for procedural thinking). 91 | 92 | And maybe AI is the currently-ultimate expression of being "declarative". We 93 | declare that we don't even know what to declare, and write a meta-declaration 94 | and hope to Lambda that it will figure out the declaration that we should have 95 | fed to the computer in the first place. 96 | * Is it being "data-oriented"? 97 | viz., choosing to work in terms of inert "literal" entities like JSON or EDN 98 | or XML or some structured binary encoding, instead of "live" objects with 99 | internal state? Asynchronous message-passing instead of synchronous remote 100 | procedure calls (whether through object graphs, or across computer networks)? 101 | 102 | Is it about adhering to the principle of referential transparency; i.e. the 103 | equivalence of evaluated functions and literal data? 104 | * Is it about "Statelessness"? 105 | No machine registers? No place-oriented "mutable" state? No pointers? No 106 | shared references? No side effects? Yes laziness? Yes append-only storage? 107 | Yes event sourcing? 108 | * Is it about "managed" environments? 109 | Language mechanisms that relieve us of the burden and perils of malloc/free? 110 | 111 | Garbage collection? Immutable persistent data structures? Type-directed 112 | compile-time memory access/use control? Multi-Version Concurrency Control? 113 | 114 | Kubernetes? 115 | * Is it about following some discipline, and maybe automating it? 116 | viz. a /system/ or a design philosophy of doing things, such as: 117 | 118 | - An accountant-like state management practice. 119 | - Carefully manipulating state only when absolutely necessary. 120 | - Hard-wiring FP traits into a programming language / system. 121 | - Choosing a strict single-process, non-branching, forward-looping-only 122 | method of flow control. 123 | - Having standard, highly general purpose compositional interfaces oriented 124 | around streaming data flow? 125 | - Eiffel-like Design-By-Contract? (Which is surprisingly "functional".) 126 | - Continuation-passing style? 127 | - ... etc? 128 | * My 2 nano BTC on the matter 129 | I think all of our popular programming systems are object-oriented /and/ 130 | imperative by default, whether explicitly or implicitly. Now they all seem 131 | to be adding "functional" looking features too. But to me, the functional-ness 132 | of a language (or a system) is not about the feature set, but fundamentally 133 | about its default (automatic) relationship with The State (of the world). 134 | ** *The "Object-Oriented" way* inexorably pushes us to clone reality. 135 | We ingest and manage as much state and behaviour as possible, in order to 136 | emulate the world. This, by construction, requires us to operate based on 137 | theories and assumptions (internal state) doomed to always lag and diverge 138 | from reality. In other words, it's a synchronization problem mixed with the 139 | impossible ideal of wanting to make the actual run-time look like the apparent 140 | run-time. Concurrency quickly reveals the difficulties of trying this. 141 | ** *The "Imperative" way* is more like doing open heart surgery. 142 | We have to get in there and manually orchestrate control flow, interrupt things, 143 | and get the whole of it to mutate in-place /while it is running/. The race 144 | condition is always imminent---will we close first, or will it stop first? 145 | We never /really/ know if the seemingly routine procedure will cause something 146 | totally unrelated to blow up in our faces this time around. Meanwhile we have 147 | very sharp instruments in hand, and have to do a lot of it by /fingerspitzengefühl/ 148 | because half the time we literally can't see where to cut or clamp or suture. 149 | I didn't train for this but I hope you have. For at least 10 years. You have, 150 | right? ... Right? 151 | ** *The "Functional" way* wants to completely invert these models. 152 | It tries to expel all system state from inside to the outside. In so doing, it 153 | immerses itself in world-state and tries to be a new conduit for different 154 | parts of outside reality to communicate, hoping to make it behave to our liking. 155 | This, by construction, forces us to think explicitly in terms of events 156 | (discrete sensing and sequencing of world updates, i.e. facts), messaging 157 | (encoding and transmitting facts as data), and time (asynchronicity, consistency, 158 | consensus). 159 | 160 | The functional way is also totally different from how we experience the world. 161 | The world is a concurrent, recurrent, parallel, fractal distributed system of 162 | systems. And it is also stochastic and full of discontinuities. We have evolved 163 | to form just-about-good-enough models of reality in our heads, in very bounded 164 | contexts, to the extent necessary for survival. These internal models smooth 165 | over all sorts of discontinuities, resist change while survival odds feel good, 166 | and determine how we behave regardless of what might actually be out there. 167 | We learn imperatively by poking and prodding the world around us while it hums 168 | along. I think this is why it takes serious effort to learn the "functional" 169 | way. We have to upend our entire mental model of how to do things in the world. 170 | ** *Maybe pure data at rest* is the only truly "functional" thing? 171 | Maybe not. Like a pure function, pure data at rest does nothing and so is 172 | useless to us when dormant. Besides, it is "pure" /only/ for the duration 173 | entropy permits its complete un-corrupted recovery. Ultimately, the laws of 174 | Physics will always win. To muddy the waters a bit more, even the purest of 175 | pure functional systems contain state; signals in flight or some in-progress 176 | computation. 177 | 178 | The only saving grace is that in a highly functional system, any run-time 179 | state is entirely recoverable, reproducible, discrete, and isolated. 180 | ** *All said, everything mutates sooner or later.* 181 | 182 | I don't know how to navigate this, except to remind myself about The Thing 183 | That Actually Matters... to always remember that The State is the frenemy. 184 | 185 | So while it pleases me that so many wish to eagerly embrace the Functional Way, 186 | it is good to be soberly mindful of scopes, lifetimes, margins, error budgets, 187 | and bounds of reality (state) and of data (information about reality). Good 188 | situational awareness will lead us to build highly functional systems that 189 | keep The State where it belongs, and still do useful things with it. 190 | ** And all /that/ said, I leave you with this prayer: 191 | #+begin_quote 192 | O Lambda the Ultimate, \\ 193 | bless the reader of these words. 194 | 195 | That their core be functional, \\ 196 | and their functions be pure. 197 | 198 | That their data be immutable, \\ 199 | so they may know the value of values. 200 | 201 | That their systems be composable, \\ 202 | so they may grow and scale with grace. 203 | 204 | That their States only mutate \\ 205 | in pleasantly surprising ways. 206 | 207 | For otherwise nothing lives. \\ 208 | Nothing evolves. 209 | 210 | In the name of the alpha, \\ 211 | the beta, and the eta... 212 | 213 | (λx.x x) (λx.x x) 214 | #+end_quote 215 | -------------------------------------------------------------------------------- /sources/posts/which-clojure-codebases-to-read-how-and-why/index.org: -------------------------------------------------------------------------------- 1 | # SHITE_META 2 | #+title: Which Clojure codebases should I read? How and why? 3 | #+summary: Newcomers to Clojure so frequently ask this question that an FAQ/Guide is being discussed, to add to the Clojure website. I struggled a lot with the question too, when starting off in Clojureland. Here are my notes and opinions. 4 | #+author: Adi 5 | #+date: 2022-04-29 6 | #+updated: 2022-04-29 7 | #+tags: clojure howto whyto 8 | #+include_toc: yes 9 | # SHITE_META 10 | 11 | Newcomers to Clojure so frequently ask this question that an FAQ/Guide is 12 | being discussed, to add to the Clojure website. See Issue #586: 13 | [[https://github.com/clojure/clojure-site/issues/586][Add FAQ or guide for example projects]]. 14 | Please add your thoughts to that ticket! 15 | 16 | This post is my (opinionated) take on it. I struggled a lot with this too. 17 | I still do from time to time, in unfamiliar territory, and these days I feel 18 | like I'm in unfamiliar territory a lot. Various Clojurians --- individuals and 19 | groups --- have been producing so much creative, diverse work over these last 20 | few years that keeping up quickly became impossible! 21 | 22 | No doubt this surfeit of creativity intimidates newcomers. The strange ideas, 23 | lingo, thinking, and writing espoused by Clojurians can seem so very alien. 24 | But despair not, for Clojureland also has a surfeit of friendly, helpful people. 25 | And very many of our codebases are small! You will be able to read them! And 26 | get help if you get stuck! 27 | 28 | This post explains what I believe I've done subconsciously over the years. It 29 | is as much an answer for somewhat experienced me as it is for the relative 30 | newcomer you! 31 | 32 | * A quick motivating example 33 | I haven't done much focused code reading recently, but semi-recently, I went 34 | down the rabbit hole of comparing "System" libraries. The details are for a 35 | separate blog post. I've placed it here as reference material to illustrate 36 | some of this post. 37 | 38 | [[https://github.com/adityaathalye/slideware/raw/master/Grokking%20Libraries%20in%20Clojureland.pdf][Grokking Libraries in Clojureland]] (PDF, slides). 39 | * Heuristics to choose a project to read 40 | This kind of code reading is best viewed as applied, directed reading designed 41 | to deeply understand creative (and destructive) ways to use an instrument, 42 | in this case, Clojure the language, its standard library, idioms, patterns, 43 | and style. 44 | 45 | The key problem here is "you don't know what you don't know". Coming up with 46 | a set of heuristics can help discover good choices. In fact, one can make a 47 | decision-making matrix of #{libraries} X #{heuristics}, like so: 48 | 49 | | Heuristic / Library | Lib A | Lib B | Lib C | 50 | |--------------------------------+-------+-------+-------| 51 | | Code size (LoC) | | | | 52 | | Code complexity (high/mid/low) | | | | 53 | | Utility | | | | 54 | | Stability (high, mid, low) | | | | 55 | | Docs | | | | 56 | | Talks | | | | 57 | | Tutorials | | | | 58 | | ... | | | | 59 | 60 | It also helps to decide a domain or area of knowledge (web/HTML, web/HTTP, 61 | algorave, databases etc.), before drawing up the decision-making matrix. 62 | 63 | Here is a set of opinions and heuristics to steal and/or riff off. 64 | ** Choosing an area of domain knowledge 65 | Knowledge about a domain or problem space is a source of massive cognitive 66 | overhead. It helps a lot to pick an area of knowledge you feel you are most 67 | comfortable with, and narrow your code search and reading to that area. 68 | 69 | For example, web programmers may want to read an HTTP library. Musicians may 70 | want to find a music synthesis codebase. Frontend people many like to read 71 | HTML / CSS parsers or generators. Database nerds may want to know how we do 72 | stuff without fancy ORMs etc. 73 | ** Project type 74 | Choose single-purpose libraries. The Clojure world is full of libraries of 75 | various sizes and responsibilities. Most of these tend to focus very sharply 76 | on one single problem, which makes it easier to build and retain complete 77 | context in one's head. These tend to be good place to start. 78 | 79 | Application code, by contrast, tends to be a complex (or complected) mix 80 | of domains, patterns, libraries. This makes it easy to get lost. 81 | 82 | Further, there is no one true way to organise Clojure apps. Often, apps 83 | don't even mirror standard conventions seen elsewhere (e.g. MVC/MVCC etc.). 84 | Clojure apps are assemblies of libraries, where each library choice comes 85 | with some technical and/or design tradeoff. Further, build tools vary. App 86 | configuration systems vary. etc. etc. many tens of moving parts. 87 | 88 | One eventually develops a sense for it all, but most of it is completely not 89 | obvious when one is just starting off. It makes way-finding really hard. 90 | You will spend lots of time just to figure out how some app is wired together. 91 | 92 | So it's better to subtract everything until you are left with a singular 93 | idea and its expression. That is, often, a single-purpose library! 94 | ** Code size 95 | Prefer libraries with as few lines of code as possible. The good news is 96 | that Clojure libraries tend to focus on a single well-defined problem, 97 | which tends to result in small /and complete/ solutions to problems. Many 98 | excellent Clojure libraries weigh in at under 1,000 LoC. 99 | 100 | With some effort, you can hope to hold the entire codebase in your head. 101 | Once that happens, your brain will discover things in diffuse mode in your 102 | shower or on a walk or something. And then you know you've struck gold! 103 | ** Code complexity 104 | Even if a library is small, it may be complex, because it address a hard 105 | problem. This is tricky to infer up-front, and that's fine. Getting stuck is 106 | part of the process. One mitigation is to skim-read the source first. If you 107 | see very deeply indented code, or lots of large functions, or lots of macros, 108 | maybe park it for later. Definitely prefer libraries without advanced macrology 109 | (unless your purpose is to understand advanced macrology :). 110 | ** Utility 111 | How much is the library used? A well-used library may be widely used, or it 112 | may be niche but heavily used. Either way, odds are good that the source has 113 | been vetted. Also it improves your chances of finding help if you get stuck. 114 | 115 | Some proxy measures like github stars, a dedicated channel in Slack or Zulip, 116 | or references in mailing list history can help judge this. If you are still 117 | uncertain, just drop a message in one of the community forums. Helpful people 118 | will help! 119 | ** Talks, docs, tutorials 120 | Are talks, docs, and tutorials available for the library, or at least the space 121 | the library addresses? The code often does not tell the full story of the 122 | "why?" of the library, the roads not taken or choices unmade. Code also tends 123 | not to convey the author's mental process. This is the highest value learning 124 | that comes from reading; viz. learning a new way to think. So knowing what 125 | knowledgeable people have been saying about the space/code is very useful. 126 | ** Beware the falsehood of "dead" repos 127 | Many in-use Clojure libraries don't see frequent (or large) updates. This is 128 | a virtue in our circles. It indicates finished-ness and stability. In fact, if 129 | you find a repo with no commits for months or years, and a "liveness advisory" 130 | on it, you /definitely/ want to read that code. That code has proven itself 131 | handsomely! 132 | * Effective way(s) to read a project 133 | This is basically a set of ways to /engage/ with the material. The programmer 134 | equivalent of textbook underlining, marginalia, scribbling notes and diagrams. 135 | ** Read the README and API docs 136 | And keep them handy. Ideally figure out the /why/ of the project before getting 137 | into the weeds, because weeds there will be. 138 | ** Use the REPL 139 | I habitually use ~clojure.repl/source~, to pull up source code for functions 140 | that are new to me. 141 | ** Learn to navigate the code 142 | Find editor functions that let you see an overview of a namespace, jump to 143 | and fro from definitions. 144 | ** /Experiment/ 145 | IMHO it is critical to /experiment/ with the code. Passive reading gets us 146 | only so far. To truly grok code one must modify and play with it! This is 147 | where one thanks oneself for choosing a focused, concise project :) 148 | ** "Comparitive Literature" approach 149 | Preferably find a space where multiple libraries exist. As long as one well 150 | used library is present, it is fine if unused ones exist too. Frequently 151 | contemporary libraries aim to overcome walls their classic brethren hit, or 152 | are novel approaches to the same problem that offer a different set of 153 | tradeoffs v/s the classics. 154 | 155 | There is much to learn from bygone classics, but only after one works through 156 | the contemporary stuff, and has several "Wait, but why?" moments. 157 | ** Alt-implementation 158 | The Black Belt move is to combine experimentation and comparative lit. and 159 | try to hack up your own alternate implementation, by purposely taking a 160 | completely different approach to representing the problem space, as compared 161 | to the library under study. 162 | * Suggested projects with short reasons why to read 163 | This is a first-cut top-of-mind list, from the top of /my/ chaotic mind. 164 | Take with a pinch of salt! 165 | 166 | Cross-reference with [[https://github.com/clojure/clojure-site/issues/586][this discussion]] 167 | where folks are trying to figure out what projects to suggest, how, and why, 168 | as part of an FAQ or a Guide at the official Clojure website. 169 | ** web/HTML/CSS 170 | - *[[https://github.com/weavejester/hiccup][weavejester/hiccup]]* to understand 171 | a natural translation of one domain (HTML) to Clojure data. Writing HTML as 172 | Clojure data is what we mean when we say "well, it's just data" or "data DSL". 173 | - *[[https://github.com/noprompt/garden][noprompt/garden]]* 174 | which does unto CSS what Hiccup does unto HTML. 175 | ** web/HTTP 176 | - *[[https://github.com/ring-clojure/ring][Ring]]*, to understand one of the 177 | most popular HTTP server abstractions in the Clojureverse. 178 | ** Clojure itself 179 | - *[[https://github.com/clojure/clojure/blob/master/src/clj/clojure/test.clj][Clojure.test]]* 180 | which is the built-in testing framework, in a surprisingly small amount of 181 | code. Also, incidentally, to start feeling OK diving into Clojure's own source. 182 | ** Database queries 183 | - *[[https://github.com/seancorfield/honeysql][honeysql]]* 184 | to grok a way to represent the Domain of SQL queries as Clojure data. 185 | ** Music maker 186 | There's lots out there that I don't know of, but... 187 | - [[https://github.com/overtone/overtone][overtone/overtone]], but it is a big project 188 | - [[https://github.com/ssrihari/ragavardhini][ssrihari/ragavardhini]] is smaller 189 | ** "System" start/stop thingy 190 | - *[[https://github.com/stuartsierra/component][stuartsierra/component]]* 191 | "Managed lifecycle of stateful objects in Clojure". 192 | ** App configuration thingy 193 | - *[[https://github.com/juxt/aero][juxt/aero]]* 194 | "A small library for explicit, intentful configuration." 195 | ** Applications designed for "copy-and-hack" 196 | As [[https://github.com/puredanger][@puredanger]] and [[https://github.com/plexus][@plexus]] have [[https://github.com/clojure/clojure-site/issues/586][written here]]: 197 | If you're wondering "what's something similar I can copy and hack on" or 198 | "what does a real project look like"? 199 | - [[https://github.com/seancorfield/usermanager-example][seancorfield/usermanager-example]] 200 | - [[https://github.com/clojureverse/clojurians-log-app][clojureverse/clojurians-log-app]] 201 | ** Large-scale repos 202 | - [[https://github.com/nasa/Common-Metadata-Repository][NASA's Common Metadata Repository]] 203 | project, just to have one's mind blown :D 204 | * Library maintainers: Would HOWTOREADMEs make sense? 205 | Hi! First, thank you for your library work! I'm just thinking aloud here... 206 | 207 | Suppose Clojure library authors write little reading guides for their projects; 208 | *"How to read me"s*? Maybe a paragraph or two that provides context like: 209 | - Suggested entry point and Meta-dot pathway 210 | - The most important namespace(s) 211 | - Interesting functions 212 | - Tests or Rich comments to try out on priority 213 | - Any known hairy-scary bits or gotchas 214 | - Perhaps a line or two suggesting "compare with Alternate Libs A, B, C" 215 | - etc. 216 | 217 | A reader may fruitfully combine this guidance with information about project 218 | purpose, rationale, and any open issues marked "beginner" etc. 219 | -------------------------------------------------------------------------------- /sources/static/css/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/static/css/.gitkeep -------------------------------------------------------------------------------- /sources/static/img/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/static/img/.gitkeep -------------------------------------------------------------------------------- /sources/static/img/220px-Lisplogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/static/img/220px-Lisplogo.png -------------------------------------------------------------------------------- /sources/static/img/Feed-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /sources/static/img/Lisp_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/static/img/Lisp_logo.png -------------------------------------------------------------------------------- /sources/static/img/Lisp_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /sources/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/static/img/favicon.ico -------------------------------------------------------------------------------- /sources/static/img/pages/index/mugshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/static/img/pages/index/mugshot.jpg -------------------------------------------------------------------------------- /sources/static/img/pages/index/scaling-stasis-death.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/static/img/pages/index/scaling-stasis-death.png -------------------------------------------------------------------------------- /sources/static/js/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adityaathalye/shite/6d30eb1df29d65945e445287798ca1ce4c987a51/sources/static/js/.gitkeep --------------------------------------------------------------------------------