<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Angela Ambroz</title><link>https://www.angelaambroz.com/posts/</link><description>Recent content in Posts on Angela Ambroz</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>© 2026 Angela Ambroz</copyright><lastBuildDate>Wed, 25 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.angelaambroz.com/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>AI Engineering ⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/ai-engineering/</link><pubDate>Wed, 25 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/ai-engineering/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/ai-engineering/book_jacket_hucdb19079652561a6e340e7bd01e6d22b_47729_330x0_resize_q75_box.jpg 330w,
/posts/ai-engineering/book_jacket_hucdb19079652561a6e340e7bd01e6d22b_47729_660x0_resize_q75_box.jpg 660w,
/posts/ai-engineering/book_jacket_hucdb19079652561a6e340e7bd01e6d22b_47729_1024x0_resize_q75_box.jpg 1024w,
/posts/ai-engineering/book_jacket_hucdb19079652561a6e340e7bd01e6d22b_47729_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/ai-engineering/book_jacket_hucdb19079652561a6e340e7bd01e6d22b_47729_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h1 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;ul>
&lt;li>Author: Chip Huyen&lt;/li>
&lt;li>Number of pages: 532&lt;/li>
&lt;li>Year published: 2025&lt;/li>
&lt;li>Year read: 2026&lt;/li>
&lt;/ul>
&lt;h1 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>Done! OK, that took a while. Overall, distilling it to a singular purpose - &lt;em>did I learn from it?&lt;/em> - the answer is, &amp;ldquo;ya.&amp;rdquo; But did I learn &lt;em>a sufficiently satisfying amount&lt;/em> from it? No, not at all. This was only a starter!&lt;/p>
&lt;h2 class="relative group">Quick overview
&lt;div id="quick-overview" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#quick-overview" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The problem with the book - as Jake said - is that it&amp;rsquo;s trying to cast a very wide net. From the intro, it seems the author, Chip Huyen, is trying to write an accessible &amp;ldquo;intro&amp;rdquo; to &amp;ldquo;AI&amp;rdquo; for software engineers, data scientists, and would-be founders. She assumes basically no special background in the technology, but - at the same time - is not aiming to write a proper undergraduate-level textbook on the subject (which is kinda what the subject requires!). As a result, it all feels very quick and surface-level.&lt;/p>
&lt;p>So what&amp;rsquo;s covered? Lemme jog my memory and see how much I retained (lol):&lt;/p>
&lt;ul>
&lt;li>&amp;ldquo;AI is cool and useful&amp;rdquo; (soooo many highlights and spicy marginalia here)&lt;/li>
&lt;li>AI mostly means large language models (LLMs), but it can also incorporate computer vision, speech-to-text, text-to-speech, and so on.&lt;/li>
&lt;li>Brief dive into LLMs and natural language processing: like, embeddings are cool, LLMs are big neural nets, the attention mechanism was a big step up, the transfer mechanism also. Even briefer mention of how all the cutting edge LLMs are basically closed-source, profit-driven moats that don&amp;rsquo;t share the neural net architecture, the weights, the training data, or the post-training steps. But I&amp;rsquo;m not bitter&amp;hellip;&lt;/li>
&lt;li>Long stretch about &amp;ldquo;evaluating AI models&amp;rdquo;, and how difficult that is. Why is it difficult? Because human knowledge is sooooo expensive and often inconveniently locked between the ears of actual humans. As a result, Huyen advises (and maybe the industry is coagulating around?) &amp;ldquo;AI judges&amp;rdquo; - aka, use an LLM to evaluate the answers of another LLM. Also, defining &amp;ldquo;better&amp;rdquo; is hard when you&amp;rsquo;re subjectively grading generated slop.&lt;/li>
&lt;li>Some cool stuff about &amp;ldquo;post-training&amp;rdquo;, fine-tuning, RAG (retrieval augmented&amp;hellip; something&amp;hellip; generation?). Aka, building on top of the &amp;ldquo;foundational models&amp;rdquo; (aka, OpenAI, Anthropic, Gemini) by either, in order of difficulty, (a) prompt &amp;ldquo;engineering&amp;rdquo; (aka, ask it nicely, ask it a lot), (b) RAG (tell it to look things up), or (c) post-training (actually train the last few layers of the neural net again). Also some intriguing stuff about smushing models together (mixture of experts). No statistical concerns here about correlated training corpuses (corpi! yay Latin of meatspace) and orthogonality and, like, what we learned with ensemble methods in traditional, pre-LLM machine learning (e.g. a Random Forest vs. a bootstrap aggregated model with correlated trees)?&lt;/li>
&lt;li>Data engineering issues - again, an alarming section about using LLMs to generate synthetic data so that we can make more LLMs. Insufficient statistical concern here!!&lt;/li>
&lt;li>Full-stack, UX research-type discussion about how to integrate your &amp;ldquo;AI&amp;rdquo; into an app with actual, human users. Some very interesting, but very brief stuff about human-computer interaction, basically?&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">OK, so the good stuff: What did I learn?
&lt;div id="ok-so-the-good-stuff-what-did-i-learn" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#ok-so-the-good-stuff-what-did-i-learn" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This was definitely a helpful &amp;ldquo;overview&amp;rdquo; book: it gave me a lot of structure to the otherwise disparate ideas I have had about LLMs. For example, I found it very helpful to disambiguate the post-training step into specific workflows like prompt &amp;ldquo;engineering&amp;rdquo;, RLHF (reinforcement learning with human feedback), RAG, teacher-student models, and so on.&lt;/p>
&lt;p>I liked the very brief history of the field, how the &amp;ldquo;Attention is All You Need&amp;rdquo; paper/attention mechanism is situated within that field (I thought it was THE thing that unlocked this strange alien intelligence, but it is apparently only A thing). I was VERY tantalized by the discussion of embeddings.&lt;/p>
&lt;p>I found the evaluation section super useful to, again, structure this otherwise ambiguous space.&lt;/p>
&lt;p>Oh yeah - and I love that this book has a repo with tons of additional resources.&lt;/p>
&lt;h2 class="relative group">The not-good stuff
&lt;div id="the-not-good-stuff" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-not-good-stuff" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I think I would have felt very differently about this book had I read it last year, pre-&lt;a href="https://www.angelaambroz.com/posts/the_ai_con">AI Con&lt;/a>, pre-AI bubble. Living in this bog of cynicism now, I couldn&amp;rsquo;t help but roll my eyes at the relatively uncritical discussions around, e.g., the fact that all the cutting edge models are closed weight. That&amp;rsquo;s not science!&lt;/p>
&lt;p>Relatedly, the &amp;ldquo;how to evaluate your model for your needs&amp;rdquo; section was frustratingly vague and unprincipled - and never called out the elephant in the room: If I can&amp;rsquo;t do any descriptive stats of the text corpuses in the training dataset, how can I, well, understand or trust anything? (I did like Huyen&amp;rsquo;s table on languages which are most disproportionately underrepresented in the main training corpuses out there: apparently Punjabi is like CRAZY underrepresented!) But the evaluation section felt like it boiled down to Vicki Boykis&amp;rsquo;s joke, that all AI evaluation is a &amp;ldquo;vibe check&amp;rdquo;.&lt;/p>
&lt;p>Similarly, the discussion of using AI judges, for example, or using synthetic training data, without a discussion of the statistical implications of that, felt really unintuitive. For example: iirc Huyen mentions how training data biases will be amplified in synthetic data creation. That&amp;rsquo;s true - and it&amp;rsquo;s important to acknowledge. But it&amp;rsquo;s only one aspect of the wider problem: when your data is highly correlated (even duplicated), then how can you extract more information from it? For example, if you use Claude 4.5 as your LLM base model - and then use Claude 4.5 (or another Claude, for that matter) prompted to be your &amp;ldquo;AI judge&amp;rdquo; for the original model - isn&amp;rsquo;t that, by definition, uninformative? Like how bootstrap aggregating (bagging, the machine learning method) can lead to correlated trees?&lt;/p>
&lt;p>Basically, I would have appreciated more foundational statistical thinking throughout. (And, in Huyen&amp;rsquo;s defense, this might be something to do with the field. For example: &lt;a href="https://arxiv.org/abs/2411.00640" target="_blank">this paper&lt;/a>, which is basically like, &amp;ldquo;Hey Anthropic/OpenAI, you should probably put error bars on your evals&amp;hellip;&amp;rdquo; Basic stuff!!!)&lt;/p>
&lt;h2 class="relative group">One more thing
&lt;div id="one-more-thing" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#one-more-thing" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Having a gorgeous barn owl on the cover is apropos as well - owls are majestic, almost mystical creatures. Like LLMs, they&amp;rsquo;re hypnotic and affecting. But let&amp;rsquo;s plz always keep in mind: when plucked of their feathers, they do look &lt;a href="https://www.reddit.com/r/Ornithology/comments/12x3iqt/this_is_what_owls_look_like_without_feather/" target="_blank">very, very silly&lt;/a>.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/216848047-ai-engineering" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Bedazzling the terminal</title><link>https://www.angelaambroz.com/posts/bedazzling-the-terminal/</link><pubDate>Sun, 01 Feb 2026 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/bedazzling-the-terminal/</guid><description>
&lt;h2 class="relative group">Eternal question: Where is my peaceful bottega?
&lt;div id="eternal-question-where-is-my-peaceful-bottega" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#eternal-question-where-is-my-peaceful-bottega" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>If I had my way, I would be working in a little 15th century Florentine bottega, carving and chipping away at my craft in blessed peace and good vibes. Having saltless bread and pasta for lunch. Tiny espressos. Admiring the Duomo. Ample time for my family. It would be solarpunk and sane and full of diversity.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/bedazzling-the-terminal/duomo_hu9bb4fbd6060cb8c5e65eb9adeaf518f3_12744068_330x0_resize_box_3.png 330w,
/posts/bedazzling-the-terminal/duomo_hu9bb4fbd6060cb8c5e65eb9adeaf518f3_12744068_660x0_resize_box_3.png 660w,
/posts/bedazzling-the-terminal/duomo_hu9bb4fbd6060cb8c5e65eb9adeaf518f3_12744068_1024x0_resize_box_3.png 1024w,
/posts/bedazzling-the-terminal/duomo_hu9bb4fbd6060cb8c5e65eb9adeaf518f3_12744068_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/bedazzling-the-terminal/duomo_hu9bb4fbd6060cb8c5e65eb9adeaf518f3_12744068_660x0_resize_box_3.png"
alt="a codex architectural drawing of the duomo in florence"
/>
&lt;/figure>
&lt;small>&lt;a href="https://en.wikipedia.org/wiki/Florence_Cathedral#/media/File:Codice_rustici,_santa_maria_del_fiore.jpg" target="_blank">&amp;ldquo;The Cathedral as depicted in the Codex Rustici of 1447&amp;rdquo;&lt;/a>&lt;/small>&lt;/p>
&lt;p>Unfortunately, I am living in a different historical context. A quote I&amp;rsquo;ve been thinking about a lot:&lt;/p>
&lt;blockquote>
&lt;p>“Might does not make right! Right makes right!”&lt;/p>
&lt;ul>
&lt;li>T.H. White, The Once and Future King&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;p>Today: Let&amp;rsquo;s pretend we&amp;rsquo;re in that bottega and do something just for the sheer pleasure of it. For the joy of tinkering and making things pretty and functional.&lt;/p>
&lt;h2 class="relative group">Moving from &lt;code>gnome-terminal&lt;/code> to &lt;a href="https://sw.kovidgoyal.net/kitty/" target="_blank">&lt;code>kitty&lt;/code>&lt;/a>
&lt;div id="moving-from-gnome-terminal-to-kittyhttpsswkovidgoyalnetkitty" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#moving-from-gnome-terminal-to-kittyhttpsswkovidgoyalnetkitty" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Tbh, I have very simple desires re: a terminal app. I just want it to:&lt;/p>
&lt;ul>
&lt;li>Allow me to scroll back&lt;/li>
&lt;li>Allow me to search the &lt;code>stdout&lt;/code> history (ideally with ctrl+F, but I&amp;rsquo;ll take what I can get)&lt;/li>
&lt;li>Allow me to copy+paste&lt;/li>
&lt;li>And then do all the normal command-line things I need to do: &lt;code>ssh&lt;/code> being principle among them.&lt;/li>
&lt;li>Have nice colors and be a bit transparent.&lt;/li>
&lt;/ul>
&lt;p>This is surprisingly hard to find! So far I&amp;rsquo;ve worked with:&lt;/p>
&lt;ul>
&lt;li>macOS&amp;rsquo;s Terminal app (well, years ago): Fine.&lt;/li>
&lt;li>gnome-terminal: Fine.&lt;/li>
&lt;li>alacritty: Fine, but characters weirdly got swallowed when I would ssh into my NAS. Annoying!&lt;/li>
&lt;/ul>
&lt;p>And now I&amp;rsquo;m trying &lt;code>kitty&lt;/code>. &lt;code>kitty&lt;/code> is by the same guy that built &lt;code>calibre&lt;/code>, which is great software. It sells itself as being &amp;ldquo;GPU-accelerated&amp;rdquo;. I&amp;rsquo;ve never really noticed my terminal being so slow I need to use a GPU to make it go fast, but, well, okay. I basically needed something to play well with ssh + tmux + copypaste, and kitty has been: okay? I appreciate having an explicit config file.&lt;/p>
&lt;h3 class="relative group">Rapprochement with &lt;code>tmux&lt;/code>
&lt;div id="rapprochement-with-tmux" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#rapprochement-with-tmux" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>This was motivated by thinking, repeatedly, that it&amp;rsquo;d be nice to have Claude/LLMs read my terminal output. Some folks at work shared their workflow of using multiple panes in &lt;code>tmux&lt;/code> with Claude Code - and telling CC to look at the other panes. This is about as close to the &amp;ldquo;chat window sidebar&amp;rdquo; experience that I think I can get. I hate using IDEs, they feel so bloated, and getting a chat window in Neovim has also been a pain. Furthermore, even if I &lt;em>did&lt;/em> get an LLM chat in my Neovim, I&amp;rsquo;d have to figure out the workflow to also work with the command line/zsh. Using multiple tmux panes - the left one keeping it as Claude Code, the right one as &amp;ldquo;everything else&amp;rdquo; (Neovim, zsh, etc) - has been great.&lt;/p>
&lt;p>I even, in an effort to Keep Up With the Times™, or at least make a good faith effort to explore the vibe code hype, made a Claude Code &amp;ldquo;command&amp;rdquo; (aka, incantation) called &lt;code>/pair-programming-setup&lt;/code> that launches the tmux pane, launches my work authentication flow, and so on. That is a handy helper indeed.&lt;/p>
&lt;h3 class="relative group">Colors
&lt;div id="colors" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#colors" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>I like pastels and neons, and picked the following:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/catppuccin/tmux" target="_blank">catppuccin/tmux&lt;/a> - &amp;ldquo;frappe&amp;rdquo; theme&lt;/li>
&lt;li>&lt;a href="https://github.com/dexpota/kitty-themes" target="_blank">dexpota/kitty-themes&lt;/a> - &amp;ldquo;Grape&amp;rdquo; theme&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Claude Code talking to itself
&lt;div id="claude-code-talking-to-itself" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#claude-code-talking-to-itself" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I guess everyone had the same idea this week: what if we made the agents talk to each other? Behold &lt;a href="https://www.404media.co/exposed-moltbook-database-let-anyone-take-control-of-any-ai-agent-on-the-site/" target="_blank">moltbook&lt;/a>. Anyway, I&amp;rsquo;m planning to run a little experiment to see how quickly the LLM disentangles itself and degrades into gibberish. But, for now, I just amused myself by having the Claude Codes talk across tmux panes.
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/bedazzling-the-terminal/screenshot_hue6eb616a2e0888b6fcdc875f44622a26_549374_330x0_resize_box_3.png 330w,
/posts/bedazzling-the-terminal/screenshot_hue6eb616a2e0888b6fcdc875f44622a26_549374_660x0_resize_box_3.png 660w,
/posts/bedazzling-the-terminal/screenshot_hue6eb616a2e0888b6fcdc875f44622a26_549374_1024x0_resize_box_3.png 1024w,
/posts/bedazzling-the-terminal/screenshot_hue6eb616a2e0888b6fcdc875f44622a26_549374_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/bedazzling-the-terminal/screenshot_hue6eb616a2e0888b6fcdc875f44622a26_549374_660x0_resize_box_3.png"
alt="a terminal running 2 panes of tmux, both with claude code"
/>
&lt;/figure>
&lt;/p></description></item><item><title>Year in review - 2025 - Books</title><link>https://www.angelaambroz.com/posts/2025_in_review_books/</link><pubDate>Wed, 10 Dec 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/2025_in_review_books/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/2025_in_review_books/jailbreak_hu2e18fcbf164b540949787579fbf217f9_4115236_330x0_resize_q75_box.jpg 330w,
/posts/2025_in_review_books/jailbreak_hu2e18fcbf164b540949787579fbf217f9_4115236_660x0_resize_q75_box.jpg 660w,
/posts/2025_in_review_books/jailbreak_hu2e18fcbf164b540949787579fbf217f9_4115236_1024x0_resize_q75_box.jpg 1024w,
/posts/2025_in_review_books/jailbreak_hu2e18fcbf164b540949787579fbf217f9_4115236_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/2025_in_review_books/jailbreak_hu2e18fcbf164b540949787579fbf217f9_4115236_660x0_resize_q75_box.jpg"
alt="My funny koreader background"
/>
&lt;/figure>
&lt;/p>
&lt;p>Okay, this feels a little bit like I&amp;rsquo;m basically working when I&amp;rsquo;m not working, but, well, here&amp;rsquo;s my write-up on what I read in 2025, as digested by a little bit of exploratory data analysis.&lt;/p>
&lt;h1 class="relative group">2025: The year I read 82+ books
&lt;div id="2025-the-year-i-read-82-books" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#2025-the-year-i-read-82-books" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>&lt;strong>&amp;#x2764;&amp;#xfe0f; Here&amp;rsquo;s the &lt;a href="https://www.goodreads.com/readingchallenges/gr/annual/2025/QTJIVldWWkNNVkpSNEcMjAyNQ" target="_blank">full list on Goodreads&lt;/a> &amp;#x1f308;&lt;/strong>&lt;/p>
&lt;p>Yes, I put the &lt;code>+&lt;/code> because I&amp;rsquo;m almost done with &lt;a href="https://billmckibben.com/books/here-comes-the-sun/" target="_blank">Bill McKibben&amp;rsquo;s &lt;em>Here Comes the Sun&lt;/em>&lt;/a> and I might have 1-2 more books in me before the year is out. But let&amp;rsquo;s analyze what I&amp;rsquo;ve completed so far.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/2025_in_review_books/solar_hu8b99268552e89512c58db9df149dc9a8_1946617_330x0_resize_q75_box.jpg 330w,
/posts/2025_in_review_books/solar_hu8b99268552e89512c58db9df149dc9a8_1946617_660x0_resize_q75_box.jpg 660w,
/posts/2025_in_review_books/solar_hu8b99268552e89512c58db9df149dc9a8_1946617_1024x0_resize_q75_box.jpg 1024w,
/posts/2025_in_review_books/solar_hu8b99268552e89512c58db9df149dc9a8_1946617_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/2025_in_review_books/solar_hu8b99268552e89512c58db9df149dc9a8_1946617_660x0_resize_q75_box.jpg"
alt="Screenshot of my Kobo, on a page from Bill McKibben"
/>
&lt;/figure>
&amp;#x261d;&amp;#xfe0f; A screenshot of &lt;em>Here Comes the Sun&lt;/em>.&lt;/p>
&lt;h1 class="relative group">&amp;#x1f4b9; Descriptive stats
&lt;div id="chart-descriptive-stats" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#chart-descriptive-stats" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;h2 class="relative group">&amp;#x1f4d6; A meta aside
&lt;div id="book-a-meta-aside" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#book-a-meta-aside" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>What I used to track books: &lt;a href="https://www.goodreads.com/" target="_blank">Goodreads&lt;/a>&lt;/li>
&lt;li>What I used to analyze my reading: &lt;a href="https://www.angelaambroz.com/posts/marimo_notebooks/">my self-hosted notebook server&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/2025_in_review_books/image6_hu97a45ec6ee40d00518624932e213e492_23241_330x0_resize_box_3.png 330w,
/posts/2025_in_review_books/image6_hu97a45ec6ee40d00518624932e213e492_23241_660x0_resize_box_3.png 660w,
/posts/2025_in_review_books/image6_hu97a45ec6ee40d00518624932e213e492_23241_1024x0_resize_box_3.png 1024w,
/posts/2025_in_review_books/image6_hu97a45ec6ee40d00518624932e213e492_23241_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/2025_in_review_books/image6_hu97a45ec6ee40d00518624932e213e492_23241_660x0_resize_box_3.png"
alt="Bar chart of my reading over time"
/>
&lt;/figure>
&lt;/p>
&lt;p>I kept up a pretty steady pace. Reading was really the only thing I did this year in the evenings. I was usually too beat from work and domesticity to do anything else. I was also recovering from a major surgery, and so that kept me sedentary and fatigued.&lt;/p>
&lt;p>&lt;a href="https://koreader.rocks/" target="_blank">KOReader&lt;/a> has a calendar view, which is super fun:
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/2025_in_review_books/calendar_hu0802ae9819455e8411de02589bbc6c83_2665885_330x0_resize_q75_box.jpg 330w,
/posts/2025_in_review_books/calendar_hu0802ae9819455e8411de02589bbc6c83_2665885_660x0_resize_q75_box.jpg 660w,
/posts/2025_in_review_books/calendar_hu0802ae9819455e8411de02589bbc6c83_2665885_1024x0_resize_q75_box.jpg 1024w,
/posts/2025_in_review_books/calendar_hu0802ae9819455e8411de02589bbc6c83_2665885_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/2025_in_review_books/calendar_hu0802ae9819455e8411de02589bbc6c83_2665885_660x0_resize_q75_box.jpg"
alt="Calendar view of my reading"
/>
&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/2025_in_review_books/image4_hud0e2b568f4d3492ba4d0adbf3fb13c98_204377_330x0_resize_box_3.png 330w,
/posts/2025_in_review_books/image4_hud0e2b568f4d3492ba4d0adbf3fb13c98_204377_660x0_resize_box_3.png 660w,
/posts/2025_in_review_books/image4_hud0e2b568f4d3492ba4d0adbf3fb13c98_204377_1024x0_resize_box_3.png 1024w,
/posts/2025_in_review_books/image4_hud0e2b568f4d3492ba4d0adbf3fb13c98_204377_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/2025_in_review_books/image4_hud0e2b568f4d3492ba4d0adbf3fb13c98_204377_660x0_resize_box_3.png"
alt="Word cloud of my book tags"
/>
&lt;/figure>
&lt;/p>
&lt;p>Behold my gloriously cheesy word cloud - thank you, Claude-embedded-in-my-Marimo-notebook.&lt;/p>
&lt;p>These are my book tags, and you can see that the vast majority of my reading was from the library (yay &lt;a href="https://libbyapp.com/" target="_blank">Libby App&lt;/a>) onto my e-reader (beloved &lt;a href="https://www.angelaambroz.com/posts/selfhosted_read_it_later/">jailbroken Kobo&lt;/a>). I made a conscious effort to read &lt;code>politics&lt;/code>, &lt;code>tech&lt;/code>, and &lt;code>climate&lt;/code>. Those are, indeed, my main preoccupations these days: authoritarianism (&lt;a href="https://www.goodreads.com/book/show/53597796-strongmen" target="_blank">Strongmen&lt;/a>), the climate crisis (&lt;a href="https://www.goodreads.com/book/show/58353189-a-half-built-garden" target="_blank">A Half-Built Garden&lt;/a>), and Big Tech (&lt;a href="https://www.goodreads.com/book/show/120806182-the-internet-con" target="_blank">The Internet Con&lt;/a>, &lt;a href="https://www.goodreads.com/book/show/217432753-the-ai-con" target="_blank">The AI Con&lt;/a>).&lt;/p>
&lt;p>The &lt;code>grihastha&lt;/code> (Sanskrit/Devanagari: गृहस्थ) is my &lt;a href="https://en.wikipedia.org/wiki/Grihastha" target="_blank">&amp;ldquo;householder&amp;rdquo;&lt;/a> shelf - aka, any book that has to do with being a parent, managing a home, domesticity. I put kid&amp;rsquo;s books, cookbooks, and general &amp;ldquo;daily dharma&amp;rdquo; books in here. Example &lt;code>grihastha&lt;/code> books in 2025: &lt;a href="https://www.goodreads.com/book/show/6534132-the-lion-and-the-mouse" target="_blank">The Lion and the Mouse&lt;/a> (wordless, watercolor picture book), &lt;a href="https://www.goodreads.com/book/show/43261110-emmy-in-the-key-of-code" target="_blank">Emmy in the Key of Code&lt;/a> (middle grade book-in-prose about a girl + computers), &lt;a href="https://www.goodreads.com/book/show/1786432.The_Home_Maker" target="_blank">The Home-Maker&lt;/a> (phenomenal, newly-rediscovered classic about gender roles).&lt;/p>
&lt;p>I&amp;rsquo;ve also tried keeping track of the historical setting of my books, since I enjoy reading about, e.g., the classical period. But I never seem to get around to it! That&amp;rsquo;s what that random &lt;code>1600s-ce&lt;/code> book is (apparently &lt;a href="https://www.goodreads.com/book/show/52318.Wild_Seed" target="_blank">Wild Seed&lt;/a>).&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/2025_in_review_books/image2_huc8ec36e2186d0ec6213d4f5f7ebf1d61_29064_330x0_resize_box_3.png 330w,
/posts/2025_in_review_books/image2_huc8ec36e2186d0ec6213d4f5f7ebf1d61_29064_660x0_resize_box_3.png 660w,
/posts/2025_in_review_books/image2_huc8ec36e2186d0ec6213d4f5f7ebf1d61_29064_1024x0_resize_box_3.png 1024w,
/posts/2025_in_review_books/image2_huc8ec36e2186d0ec6213d4f5f7ebf1d61_29064_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/2025_in_review_books/image2_huc8ec36e2186d0ec6213d4f5f7ebf1d61_29064_660x0_resize_box_3.png"
alt="Bar chart of the publication year"
/>
&lt;/figure>
&lt;/p>
&lt;p>Here&amp;rsquo;s a histogram of the publication year of the books I read: huge recency bias, ha.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/2025_in_review_books/image3_huf1d79b413c1ab447e98c5c01959576b2_28237_330x0_resize_box_3.png 330w,
/posts/2025_in_review_books/image3_huf1d79b413c1ab447e98c5c01959576b2_28237_660x0_resize_box_3.png 660w,
/posts/2025_in_review_books/image3_huf1d79b413c1ab447e98c5c01959576b2_28237_1024x0_resize_box_3.png 1024w,
/posts/2025_in_review_books/image3_huf1d79b413c1ab447e98c5c01959576b2_28237_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/2025_in_review_books/image3_huf1d79b413c1ab447e98c5c01959576b2_28237_660x0_resize_box_3.png"
alt="Pie chart of predicted gender"
/>
&lt;/figure>
&lt;/p>
&lt;p>And a slightly cursed pie chart of predicted gender - using the Python package &lt;a href="https://github.com/lead-ratings/gender-guesser" target="_blank">gender-guesser&lt;/a> to predict gender using an author&amp;rsquo;s first name. That package is super old (2015!), and hasn&amp;rsquo;t really gotten the memo on gender diversity. But - meh - it looks like I did decent on reading a pretty even spread?&lt;/p>
&lt;h1 class="relative group">No more data, now only vibes
&lt;div id="no-more-data-now-only-vibes" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#no-more-data-now-only-vibes" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>I have already written somewhere on the Internet that I love my e-reader. Oh, how I love my e-reader. People who say &amp;ldquo;I love the smell of books&amp;rdquo; can bite me. They don&amp;rsquo;t actually like reading, they like the aesthetics of reading! And, for what it&amp;rsquo;s worth, I like the smell of my little Kobo off-gassing its electronic juices.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/2025_in_review_books/soccer_hu854d4d441dfb87ac7849fc0e89cab619_3847365_330x0_resize_q75_box.jpg 330w,
/posts/2025_in_review_books/soccer_hu854d4d441dfb87ac7849fc0e89cab619_3847365_660x0_resize_q75_box.jpg 660w,
/posts/2025_in_review_books/soccer_hu854d4d441dfb87ac7849fc0e89cab619_3847365_1024x0_resize_q75_box.jpg 1024w,
/posts/2025_in_review_books/soccer_hu854d4d441dfb87ac7849fc0e89cab619_3847365_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/2025_in_review_books/soccer_hu854d4d441dfb87ac7849fc0e89cab619_3847365_660x0_resize_q75_box.jpg"
alt="Me reading the Vegetarian at soccer practice"
/>
&lt;/figure>
&lt;/p>
&lt;p>This image fills me with joy. Someone interrupted me while I was taking this picture. Mortifying.&lt;/p>
&lt;h2 class="relative group">I read more fiction this year
&lt;div id="i-read-more-fiction-this-year" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#i-read-more-fiction-this-year" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I am a little bit allergic to &amp;ldquo;mainstream&amp;rdquo;, aka literary fiction. I mostly read non-fiction and science fiction. That has been my preference for nigh 20 years now (!). Anyway, this year I intentionally and unintentionally read a bit more &amp;ldquo;prestige&amp;rdquo;, lit fic: &lt;a href="https://www.goodreads.com/book/show/4631.A_Moveable_Feast" target="_blank">A Moveable Feast&lt;/a> (and, as a chaser, some fanfic about it via &lt;a href="https://www.goodreads.com/book/show/8683812-the-paris-wife" target="_blank">The Paris Wife&lt;/a>), &lt;a href="https://www.goodreads.com/book/show/25489025-the-vegetarian" target="_blank">The Vegetarian&lt;/a>, &lt;a href="https://www.goodreads.com/book/show/701724.Fellow_Travelers" target="_blank">Fellow Travellers&lt;/a>. All were quite good. This fiction stuff, eh! Not bad!&lt;/p>
&lt;h2 class="relative group">I read some remarkable historical artifacts
&lt;div id="i-read-some-remarkable-historical-artifacts" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#i-read-some-remarkable-historical-artifacts" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Namely:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.goodreads.com/book/show/1786432.The_Home_Maker" target="_blank">The Home-Maker&lt;/a> by Dorothy Canfield Fisher - Originally published in 1924, then forgotten (?!), then re-published by &lt;a href="https://persephonebooks.co.uk/" target="_blank">Persephone Books&lt;/a> (a British publisher that &amp;ldquo;reprints neglected fiction and non-fiction, mostly by women writers and mostly dating from the mid-twentieth century&amp;rdquo;). I think I found this via &lt;a href="https://www.kobo.com/us/en/ebook/the-home-maker-3" target="_blank">Kobo&amp;rsquo;s recommendation&lt;/a>. It was phenomenal and was an anchoring text for this year. Can be paired with the equally phenomenal &lt;a href="https://www.goodreads.com/book/show/414923.Counting_for_Nothing" target="_blank">Counting for Nothing&lt;/a> by Marilyn Waring, which expanded my consciousness.&lt;/li>
&lt;li>&lt;a href="www.goodreads.com/book/show/131366147-the-oppermans">The Oppermans&lt;/a> by Lion Feuchtwanger - Originally published in 1933. A book about the Holocaust &lt;em>written before the Holocaust&lt;/em>. Tremendously affecting. Can be paired with the equally brilliant &lt;a href="https://www.goodreads.com/book/show/41940427-learning-from-the-germans?from_search=true&amp;amp;from_srp=true&amp;amp;qid=YigrrHEzq6&amp;amp;rank=1" target="_blank">Learning from the Germans&lt;/a> by Susan Neiman (non-fiction political philosophy) and &lt;a href="https://www.goodreads.com/book/show/387373.Swastika_Night" target="_blank">Swastika Night&lt;/a> by Katherine Burdekin (sci-fi published in 1935 about the Holocaust, again, &lt;em>before the Holocaust&lt;/em>).&lt;/li>
&lt;/ul>
&lt;p>All five of the above books really affected my thinking. They were those instant-classic-reads that I ended up citing all the damn time, to everyone. They were those types of books where I&amp;rsquo;m shocked I only read just now, since they feel so deeply embedded in my brain.&lt;/p>
&lt;p>Anyway, some other stellar, brain-embedding books were:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.goodreads.com/book/show/198563692-boymom?from_search=true&amp;amp;from_srp=true&amp;amp;qid=Rh4NIHgiBu&amp;amp;rank=1" target="_blank">BoyMom&lt;/a> by Ruth Whippman - We need to put emotions back into heteronormative masculinity, for everyone&amp;rsquo;s sakes.&lt;/li>
&lt;li>&lt;a href="https://www.goodreads.com/book/show/50364458-the-tyranny-of-merit?ref=nav_sb_ss_2_8" target="_blank">The Tyranny of Merit&lt;/a> by Michael Sandel - Hey, crazy idea, what if we tried to get equality of &lt;em>outcomes&lt;/em>, not just opportunity? &amp;#x1f937;&lt;/li>
&lt;li>&lt;a href="https://www.goodreads.com/book/show/22514020-neurotribes?ref=nav_sb_ss_1_11" target="_blank">NeuroTribes&lt;/a> by Steve Silberman - A deep, compassionate history of autism, and its two competing narratives (&amp;ldquo;we should fix it&amp;rdquo; vs. &amp;ldquo;we should make the world more welcoming of it&amp;rdquo;).&lt;/li>
&lt;li>&lt;a href="https://www.goodreads.com/book/show/217432753-the-ai-con?from_search=true&amp;amp;from_srp=true&amp;amp;qid=JmZGn05nB8&amp;amp;rank=1" target="_blank">The AI Con&lt;/a> by Emily Bender and Alex Hanna - The spiritual sequel to &lt;a href="https://www.goodreads.com/book/show/28186015-weapons-of-math-destruction?ref=nav_sb_ss_1_27" target="_blank">Weapons of Math Destruction&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.goodreads.com/book/show/13456414-a-short-stay-in-hell?ref=nav_sb_ss_1_18" target="_blank">A Short Stay in Hell&lt;/a> by Steven Peck - Super-short philosophical fiction with the bleakest, blackest of humors.&lt;/li>
&lt;/ul>
&lt;h1 class="relative group">Planning for 2026
&lt;div id="planning-for-2026" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#planning-for-2026" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;h2 class="relative group">What genres?
&lt;div id="what-genres" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#what-genres" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I usually have ambitions to read more widely. At the same time, I &lt;em>also&lt;/em> keep making promises to myself to always have certain themes in rotation: &lt;code>dharma&lt;/code> (aka, anything Buddhist or philosophical), &lt;code>fem&lt;/code> (anything feminist or&amp;hellip; uh, philosophical), &lt;code>tech&lt;/code> (for fun), &lt;code>scifi&lt;/code> (for more fun), &lt;code>climate&lt;/code> (for 🌎).That&amp;rsquo;s a lot!&lt;/p>
&lt;p>I tried reading some straight-up romance this year - after last year&amp;rsquo;s highly successful excursion into the genre via &lt;a href="https://www.goodreads.com/book/show/578190.Zemindar?from_search=true&amp;amp;from_srp=true&amp;amp;qid=gnYSxkGz31&amp;amp;rank=1" target="_blank">Zemindar&lt;/a> (oh, Zemindar, my love). But I couldn&amp;rsquo;t do it: I couldn&amp;rsquo;t suspend my disbelief. Similarly, I still struggle with mysteries - it always feels less like a puzzle, more like an unfair riddle.&lt;/p>
&lt;h2 class="relative group">How to find books?
&lt;div id="how-to-find-books" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-to-find-books" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Right now, I mostly find new things to read via Goodreads&amp;rsquo;s &amp;ldquo;Readers &lt;em>also&lt;/em> enjoyed&amp;rdquo; + recommendations out in the wild (blogs, newspapers, etc) + &lt;a href="https://www.angelaambroz.com/posts/llm_book_recsys/">my LLM librarian&lt;/a>. The Kobo store&amp;rsquo;s recommender system has also been punching above its weight; I think that&amp;rsquo;s how I discovered the very enjoyable near future cli-fi novellas &lt;a href="https://www.goodreads.com/book/show/56996758-the-annual-migration-of-clouds?ac=1&amp;amp;from_search=true&amp;amp;qid=lcx0ypboTJ&amp;amp;rank=2" target="_blank">by Premee Mohamed&lt;/a>.&lt;/p>
&lt;p>Onwards and upwards! (Wow, I just re-read &lt;a href="https://www.angelaambroz.com/posts/best_books_of_2018/">my yearly review of books from 2018&lt;/a> and I concluded &lt;em>that&lt;/em> one with &amp;ldquo;Onwards!&amp;rdquo; My brain really has only a handful of subroutines, sigh&amp;hellip;)&lt;/p></description></item><item><title>Migrating from Wallabag to Readeck</title><link>https://www.angelaambroz.com/posts/readeck/</link><pubDate>Thu, 04 Dec 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/readeck/</guid><description>&lt;p>Wow, 2025 really has been the Year of &lt;del>Linux&lt;/del> Self-hosting! This stuff is the gift that keeps on giving.&lt;/p>
&lt;h1 class="relative group">The problem space: Reading it later in comfort and style
&lt;div id="the-problem-space-reading-it-later-in-comfort-and-style" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-problem-space-reading-it-later-in-comfort-and-style" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>My latest project has been tinkering with my read-it-later flow. I realized I had several quirks in my workflow that, ideally, my tooling would reflect (and these are roughly ranked by importance):&lt;/p>
&lt;ol>
&lt;li>I knew I always preferred reading on e-ink. So something that could sync to my Kobo was essential.&lt;/li>
&lt;li>Similarly, I needed the ability to collect links from my preferred browser (Firefox) (highest priority), my phone (second priority), and my &lt;a href="https://www.angelaambroz.com/posts/one_true_rss">FreshRSS instance&lt;/a> (last priority, kind of redundant).&lt;/li>
&lt;li>Another must-have was archiving: I didn&amp;rsquo;t want link rot to eat away at my collection.&lt;/li>
&lt;li>A &amp;ldquo;nice to have&amp;rdquo; would be the ability to highlight and sync highlights.&lt;/li>
&lt;li>A &lt;em>really&lt;/em> &amp;ldquo;nice to have&amp;rdquo; would be integrating it with my Anki workflow too.&lt;/li>
&lt;li>A somewhat ambivalent &amp;ldquo;nice to have&amp;rdquo; was some LLM integration which would let me organize or interact with my collection using natural language. (&lt;a href="https://karakeep.app/" target="_blank">Karakeep&lt;/a> does this.)&lt;/li>
&lt;/ol>
&lt;p>I also realized I kind of had two distinct use cases. One was for my &lt;strong>reading&lt;/strong>, whether that be for work (where e-ink and highlighting were crucial) or for pleasure (where just e-ink was important). Another use case was for &lt;strong>collecting&lt;/strong>, vibing, mood boarding, you know, &lt;em>Pinteresting&lt;/em>. I never really used Pinterest, and instead have historically just scattered my little treasure trove of Internet tschotschkes in various places: my Reddit saves, my hard drive &lt;code>Pictures/&lt;/code> folder, and so on. I did like the idea of gathering my &lt;em>visual&lt;/em> media someplace.&lt;/p>
&lt;h2 class="relative group">My personal pain points on Wallabag
&lt;div id="my-personal-pain-points-on-wallabag" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#my-personal-pain-points-on-wallabag" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I already &lt;a href="https://www.angelaambroz.com/posts/selfhosted_read_it_later">blogged about it&lt;/a> seven months ago, but some pain points had been coming up with my flow. First: I broke the CSS and JavaScript on my self-hosted Wallabag web app instance, because I needed the PHP server to identify itself using &lt;em>both&lt;/em> my local-network IP address &lt;em>and&lt;/em> its externally available, VPN IP address. The environment variable which handles this, &lt;code>SYMFONY__ENV__DOMAIN_NAME&lt;/code>, gets treated as a string in the later PHP code, rather than that later code just using a relative reference. So having an ugly, semi-functional Wallabag web app was already pretty sad (and severely limited my usage of it).&lt;/p>
&lt;p>But I was like, fine. Whatever. The main use case, for me, is the e-ink.&lt;/p>
&lt;p>And here&amp;rsquo;s the second pain point, which kinda annoyed me increasingly over time. The KOReader Wallabag plugin lets you sync to a Wallabag server. Fine, good. In theory. But! You&amp;rsquo;re very limited in &lt;em>how&lt;/em> that syncing occurs. You can only specify the number of unread articles you&amp;rsquo;d like synced, and to which folder on your e-reader, and that&amp;rsquo;s it. What this meant was that I was often syncing 50 or 100 articles, just to see what I had of interest to read. This was certainly tedious. And it felt inefficient, especially as I was having a blast and much better user experience using &lt;a href="https://en.wikipedia.org/wiki/Open_Publication_Distribution_System" target="_blank">OPDS&lt;/a> for my Calibre-hosted collection. Seriously, &lt;a href="https://opds.io/" target="_blank">OPDS&lt;/a>, I love you.&lt;/p>
&lt;h2 class="relative group">Choosing Readeck
&lt;div id="choosing-readeck" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#choosing-readeck" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>After plunging into research again - and seriously considering &lt;a href="https://karakeep.app/" target="_blank">Karakeep&lt;/a> again - I ended up landing on &lt;a href="https://readeck.org/en/" target="_blank">Readeck&lt;/a>. The main reasoning was Readeck&amp;rsquo;s promises of a flexible syncing solution to e-ink (and how that was, relatively, more important to me than the LLM integration in Karakeep). So, on a slow weekend, I gave it a shot. The rest of this blog post is less a tutorial, and more documentation for my future self.&lt;/p>
&lt;h1 class="relative group">Not-a-tutorial: Getting Readeck set up
&lt;div id="not-a-tutorial-getting-readeck-set-up" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#not-a-tutorial-getting-readeck-set-up" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;h2 class="relative group">The brains: Setting up the Readeck server (20 mins)
&lt;div id="the-brains-setting-up-the-readeck-server-20-mins" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-brains-setting-up-the-readeck-server-20-mins" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This was the usual flow of picking one of my &amp;ldquo;hosts&amp;rdquo; (a NAS or a Raspberry Pi) and setting up a Docker container. To do this, I relied on the clear and brief &lt;a href="https://readeck.org/en/docs/" target="_blank">docs&lt;/a> and used a Docker compose file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">app&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">codeberg.org/readeck/readeck:latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">container_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">readeck&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="m">8000&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="m">8000&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Defines the application log level. Can be error, warn, info, debug.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">READECK_LOG_LEVEL&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">info&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># The IP address on which Readeck listens.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">READECK_SERVER_HOST&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># The TCP port on which Readeck listens. Update container port above to match (right of colon).&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">READECK_SERVER_PORT&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">8000&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Easier to read log format&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">READECK_LOG_FORMAT&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">text&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Optional, the URL prefix of Readeck.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># READECK_SERVER_PREFIX: &amp;#34;/&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">/path/to/docker/readeck:/readeck&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restart&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">unless-stopped&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">healthcheck&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">test&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;CMD&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;/bin/readeck&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;healthcheck&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;-config&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;config.toml&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">interval&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">30s&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">timeout&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">2s&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">retries&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then it&amp;rsquo;s &lt;code>docker-compose up -d&lt;/code> and, a few minutes later, navigating to &lt;code>http://whatever_the_host_is:8000&lt;/code> and making the first admin account. The browser extensions are official and maintained by the Readeck team (guy?) and they work fine. This part was fast and easy, maybe 20 minutes tops.&lt;/p>
&lt;h2 class="relative group">Client #1: My Android phone (1 hr)
&lt;div id="client-1-my-android-phone-1-hr" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#client-1-my-android-phone-1-hr" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h3 class="relative group">Sending articles
&lt;div id="sending-articles" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#sending-articles" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Technically, there are a few options for getting an Android phone set up to talk to a Readeck server. The docs &lt;a href="https://readeck.org/en/docs/faq" target="_blank">mention&lt;/a> an Android app, &lt;a href="https://codeberg.org/gollyhatch/eckard" target="_blank">Eckard&lt;/a>, but - upon inspection - it seems &lt;em>very&lt;/em> WIP and not available on &lt;a href="https://f-droid.org/en/" target="_blank">F-Droid&lt;/a>.&lt;/p>
&lt;p>Next, I found some random app on GitHub that claimed to be an Android client for Readeck. I won&amp;rsquo;t link it, because it didn&amp;rsquo;t work for me. Maybe another WIP.&lt;/p>
&lt;p>Finally, the docs recommend configuring &lt;a href="https://github.com/Waboodoo/HTTP-Shortcuts" target="_blank">HTTP Shortcuts&lt;/a>, an Android app that lets you make HTTP requests from your home screen. Or something. Yes, it&amp;rsquo;s random. Anyway, I imported - and slightly modified - &lt;a href="https://codeberg.org/attachments/9d07b938-8d05-4553-a28b-4b919d71799e" target="_blank">this template file&lt;/a>. After test-sending some articles from around my phone, this worked fine.&lt;/p>
&lt;h3 class="relative group">Reading articles
&lt;div id="reading-articles" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#reading-articles" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>&lt;del>This one&amp;rsquo;s still a WIP, and I&amp;rsquo;ll probably just use the website.&lt;/del> Yep - just using my phone&amp;rsquo;s Firefox, saving it as a bookmark on my homescreen. It feels snappy and fine. Nice to not have a middleman-app!&lt;/p>
&lt;h2 class="relative group">Client #2: My Kobo (20 mins)
&lt;div id="client-2-my-kobo-20-mins" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#client-2-my-kobo-20-mins" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Readeck really shined in how easy it was to set up the link between my Kobo (running KOReader) and Readeck&amp;rsquo;s OPDS server. You make an API key in Readeck&amp;rsquo;s web app, copy that to your Kobo (this was the most annoying bit), and then log into it from your &amp;ldquo;Add new OPDS connection&amp;rdquo; screen. For my future self, here were the steps:&lt;/p>
&lt;ol>
&lt;li>The URL is: &lt;code>http://local_network_ip_address:8001/opds&lt;/code>&lt;/li>
&lt;li>You need to enter your Readeck username and the API token.&lt;/li>
&lt;li>You can download the API token from the Readeck UI, as &lt;code>readeck-token.txt&lt;/code>. I copied this text file over to the Kobo by opening up its SSH port and SCPing it over:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">scp ~/Downloads/readeck-token.txt root@my_kobo_ip:/mnt/onboard
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And, fyi, long-pressing the API key didn&amp;rsquo;t work (it wanted to look it up in my dictionaries). Instead, a more swipey highlighting gesture worked.&lt;/p>
&lt;h2 class="relative group">Migrating my Wallabag articles to Readeck (1 hour)
&lt;div id="migrating-my-wallabag-articles-to-readeck-1-hour" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#migrating-my-wallabag-articles-to-readeck-1-hour" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The Readeck web app technically has an &amp;ldquo;import from Wallabag&amp;rdquo; function. It wants to connect to Wallabag via its API. But, heavens, you ask me to figure out Docker networking? No no no. I will simply export.&lt;/p>
&lt;p>And export I did! Deep in the recesses of my Wallabag instance, I found the 60MB-sized &lt;code>wallabag.sqlite&lt;/code> database. There you are, sucker! I grabbed it, inspected it:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sqlite3&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">wallabag&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">sqlite&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">schema&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">wallabag_entry&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">CREATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">TABLE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">wallabag_entry&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">INTEGER&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">PRIMARY&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">KEY&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">AUTOINCREMENT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">INTEGER&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">title&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CLOB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CLOB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">is_archived&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BOOLEAN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">is_starred&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BOOLEAN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CLOB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">created_at&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">updated_at&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">mimetype&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CLOB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">domain_name&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CLOB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">preview_picture&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CLOB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">uid&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">VARCHAR&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">23&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">http_status&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">VARCHAR&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">published_at&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">starred_at&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">origin_url&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CLOB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">archived_at&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">DATETIME&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">given_url&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CLOB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">reading_time&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">INTEGER&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NOT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">published_by&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">CLOB&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLLATE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BINARY&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">--(DC2Type:array)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And exported it to a CSV, with the gentlest sprinkling of data cleaning that was needed (very, very minimal):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sqlite3 wallabag.sqlite -csv -header &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="s2">&amp;#34;SELECT url, title, CASE WHEN is_archived = 1 THEN &amp;#39;archive&amp;#39; ELSE NULL END as state, null as created, null as labels FROM wallabag_entry;&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &amp;gt; wallabag_export.csv
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Readeck chomped through this &lt;code>.csv&lt;/code> with minimal fuss, though I am a &lt;em>little&lt;/em> distressed that it could only match about ~60% of my articles. I&amp;rsquo;ll debug this&amp;hellip; someday.&lt;/p>
&lt;p>By this point, I was basically up and running! I spent a few days just getting used to its flows, and mostly enjoying it. Then came a couple &lt;em>very&lt;/em> nice surprises!&lt;/p>
&lt;h1 class="relative group">Delightful surprises: Showcasing Readeck at its best
&lt;div id="delightful-surprises-showcasing-readeck-at-its-best" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#delightful-surprises-showcasing-readeck-at-its-best" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;h2 class="relative group">Surprise #1: Readeck &amp;gt; Save this image
&lt;div id="surprise-1-readeck--save-this-image" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#surprise-1-readeck--save-this-image" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Dude! It&amp;rsquo;s like a self-hosted mood board! For 10 years now, I&amp;rsquo;ve been occasionally adding gorgeous art and little delights to my Reddit saves. This was really not ideal, though, because of both Reddit &lt;a href="https://en.wikipedia.org/wiki/Link_rot" target="_blank">link rot&lt;/a> and, just, not actually &amp;ldquo;owning&amp;rdquo; a copy of that data. I was definitely feeling anxious about this. There were a &lt;em>lot&lt;/em> of treasures there (&lt;a href="https://www.reddit.com/r/museum/" target="_blank">r/museum&lt;/a> and &lt;a href="https://www.reddit.com/r/UtterlyUniquePhotos/" target="_blank">r/UtterlyUniquePhotos&lt;/a> and &lt;a href="https://www.reddit.com/r/ImaginaryLandscapes/" target="_blank">r/ImaginaryLandscapes&lt;/a>, my loves). But! With Readeck, it was easy peasy to save all these gorgeous pieces of art - &lt;em>with attribution and a link to what they are&lt;/em> - into a lovely self-hosted gallery! WONDERFUL.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/readeck/2025-12-04_22-02_hu24cad209096e09f13f420e8fdcee35ba_798083_330x0_resize_box_3.png 330w,
/posts/readeck/2025-12-04_22-02_hu24cad209096e09f13f420e8fdcee35ba_798083_660x0_resize_box_3.png 660w,
/posts/readeck/2025-12-04_22-02_hu24cad209096e09f13f420e8fdcee35ba_798083_1024x0_resize_box_3.png 1024w,
/posts/readeck/2025-12-04_22-02_hu24cad209096e09f13f420e8fdcee35ba_798083_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/readeck/2025-12-04_22-02_hu24cad209096e09f13f420e8fdcee35ba_798083_660x0_resize_box_3.png"
alt="my art gallery on readeck"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Surprise #2: Readeck for work research
&lt;div id="surprise-2-readeck-for-work-research" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#surprise-2-readeck-for-work-research" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Today, I had a major brainwave. I wanted to learn a bit more about &lt;a href="https://en.wikipedia.org/wiki/Sequential_analysis" target="_blank">sequential testing&lt;/a>. My normal workflow here would be to, first, collect some things to read or watch: ideally, academic articles, industry blog posts, YouTube lectures, and documentation. I would normally dump all these links into my &lt;a href="https://www.angelaambroz.com/posts/obsidian/">Obsidian&lt;/a>, take my notes there and drop a link to what I read. With blog posts, especially, I&amp;rsquo;ve been annoyed that I can&amp;rsquo;t highlight. Well, today, I realized&amp;hellip; &lt;em>I can&lt;/em>.&lt;/p>
&lt;p>So, new workflow:&lt;/p>
&lt;ol>
&lt;li>Instead of dumping everything I found into an Obsidian &amp;ldquo;reading list&amp;rdquo; note, I saved them all to Readeck.&lt;/li>
&lt;li>In Readeck, I created a collection for work-related readings. I loved this because I could group together articles &lt;em>and&lt;/em> videos. I could also label them (manually&amp;hellip; LLM would be nice here&amp;hellip;) and get time estimates. For videos, I could also immediately get the transcript (of so-so quality). And it was all searchable! Glory be.&lt;/li>
&lt;li>Finally, I could highlight these posts at my leisure - and view those highlights on their own, in their own highlights tab. (I can imagine using this for quickly generating Anki cards.)&lt;/li>
&lt;li>I really &lt;em>loved&lt;/em> the informative sidebar that Readeck has in its UI (bravissimi, devs) - telling me the authors, the original link, the posting date. But I just discovered the coup de grace: an outbound links list at the end! 👏🏻&lt;/li>
&lt;/ol>
&lt;p>This was really wonderful, and made accumulating knowledge for my, ahem, Knowledge Work, so much easier and more organized. Here&amp;rsquo;s some screenshots:&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/readeck/2025-12-04_21-09_hu3154aff73c8033055dd3b79d1ab8d9c7_108390_330x0_resize_box_3.png 330w,
/posts/readeck/2025-12-04_21-09_hu3154aff73c8033055dd3b79d1ab8d9c7_108390_660x0_resize_box_3.png 660w,
/posts/readeck/2025-12-04_21-09_hu3154aff73c8033055dd3b79d1ab8d9c7_108390_1024x0_resize_box_3.png 1024w,
/posts/readeck/2025-12-04_21-09_hu3154aff73c8033055dd3b79d1ab8d9c7_108390_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/readeck/2025-12-04_21-09_hu3154aff73c8033055dd3b79d1ab8d9c7_108390_660x0_resize_box_3.png"
alt="screenshot"
/>
&lt;/figure>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/readeck/2025-12-04_21-10_hu9552a7a80222bd5b5b9579a8bdb5949c_278728_330x0_resize_box_3.png 330w,
/posts/readeck/2025-12-04_21-10_hu9552a7a80222bd5b5b9579a8bdb5949c_278728_660x0_resize_box_3.png 660w,
/posts/readeck/2025-12-04_21-10_hu9552a7a80222bd5b5b9579a8bdb5949c_278728_1024x0_resize_box_3.png 1024w,
/posts/readeck/2025-12-04_21-10_hu9552a7a80222bd5b5b9579a8bdb5949c_278728_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/readeck/2025-12-04_21-10_hu9552a7a80222bd5b5b9579a8bdb5949c_278728_660x0_resize_box_3.png"
alt="screenshot"
/>
&lt;/figure>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/readeck/2025-12-04_21-10_1_hu4eb2702fae306cb1e2b10fc3ca15f450_103869_330x0_resize_box_3.png 330w,
/posts/readeck/2025-12-04_21-10_1_hu4eb2702fae306cb1e2b10fc3ca15f450_103869_660x0_resize_box_3.png 660w,
/posts/readeck/2025-12-04_21-10_1_hu4eb2702fae306cb1e2b10fc3ca15f450_103869_1024x0_resize_box_3.png 1024w,
/posts/readeck/2025-12-04_21-10_1_hu4eb2702fae306cb1e2b10fc3ca15f450_103869_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/readeck/2025-12-04_21-10_1_hu4eb2702fae306cb1e2b10fc3ca15f450_103869_660x0_resize_box_3.png"
alt="screenshot"
/>
&lt;/figure>
&lt;/p></description></item><item><title>Uncanny Valley - ⭐⭐</title><link>https://www.angelaambroz.com/posts/uncanny_valley/</link><pubDate>Tue, 11 Nov 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/uncanny_valley/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/uncanny_valley/book_jacket_hufcbbb5df6ccf38c32db0ed7af58b6e00_21737_330x0_resize_q75_box.jpg 330w,
/posts/uncanny_valley/book_jacket_hufcbbb5df6ccf38c32db0ed7af58b6e00_21737_660x0_resize_q75_box.jpg 660w,
/posts/uncanny_valley/book_jacket_hufcbbb5df6ccf38c32db0ed7af58b6e00_21737_1024x0_resize_q75_box.jpg 1024w,
/posts/uncanny_valley/book_jacket_hufcbbb5df6ccf38c32db0ed7af58b6e00_21737_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/uncanny_valley/book_jacket_hufcbbb5df6ccf38c32db0ed7af58b6e00_21737_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Anna Wiener&lt;/li>
&lt;li>Number of pages: 281&lt;/li>
&lt;li>Year published: 2020&lt;/li>
&lt;li>Year read: 2025&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Hm, an interesting memoir that I consumed like gossip or candy - but am unsure if I&amp;rsquo;d recommend?&lt;/p>
&lt;p>This is a memoir of a very specific experience: being a relatively privileged, liberal arts/literary fiction-type white lady going to work in Silicon Valley in the 2010s. I am a white lady who went to work for tech in the 2010s (though, twist!, I hate literary fiction); I can confirm a lot of the cultural/anthropological reportage. The socio-economic and political points are specific to her perspective. And I totally get it.&lt;/p>
&lt;p>But! A couple criticisms:&lt;/p>
&lt;p>First, Wiener makes this interesting choice to anonymize EVERYTHING. It&amp;rsquo;s not Meta, it&amp;rsquo;s &amp;ldquo;the social network everybody hates&amp;rdquo;. It&amp;rsquo;s not Amazon, it&amp;rsquo;s &amp;ldquo;the former e-book seller megacorp&amp;rdquo; (or whatever, I can&amp;rsquo;t remember that one). In some cases, this is illuminating. Okay, in ONE case, it was illuminating: when she described Apple&amp;rsquo;s marketing of itself for its liberal/tolerant values, while its supply chain is an extractive, exploitative human rights nightmare (conflict minerals in the Congo; Foxconn, etc). THAT moment gave me pause.&lt;/p>
&lt;p>But the rest of the time, the anonymization is just annoying. And weirdly gatekeeping? I kept asking myself: who is the audience for this?&lt;/p>
&lt;p>For tech &amp;ldquo;insiders&amp;rdquo;, aka people who work in the industry or pay close attention to it, the anonymization is weird because it&amp;rsquo;s usually VERY clear who she&amp;rsquo;s talking about: GitHub, the Electronic Frontier Foundation, etc. For folks NOT in the industry, it&amp;rsquo;s just&amp;hellip; not helpful? Like, I&amp;rsquo;m all for educating people who are not in tech about tech&amp;rsquo;s wicked, perverted ways (too numerous to mention). But we can only really do that if we name names! Being oblique just isn&amp;rsquo;t helpful. (And here is one person&amp;rsquo;s &lt;a href="https://medium.com/@rilka/an-exhaustive-reverse-glossary-of-the-65-oblique-references-in-anna-wieners-uncanny-valley-70961e9c5d81">helpful public good: a &amp;ldquo;reverse engineered&amp;rdquo; dictionary of all the references&lt;/a>.)&lt;/p>
&lt;p>Another BIG missing piece that bothered me quite a lot is the total absence of the joy of, well, tech. Wiener is coming from a liberal arts perspective (and the points she makes about the different work cultures in the NYC publishing industry vs. SF startups were very on-point and authentic to my experiences coming from the non-profit world). She&amp;rsquo;s not particularly interested in learning how to code. She gives it a try one weekend, working through tutorials, and finds it pleasant but only gratifying to her &amp;ldquo;obsessive compulsive tendencies, [her] perfectionism&amp;rdquo;. She seems to imply that even the joy of coding is, in some way, corrupt or corrupting.&lt;/p>
&lt;p>As a perfectionist with diagnosed OCD (!), this, well, hurt my feelings! And missed the mark COMPLETELY. (Correlation is not causation&amp;hellip;)&lt;/p>
&lt;p>Because coding is, for me, a creative craft, akin to making music! YES. And I know several musicians-turned-coders. Music and coding both create something out of nothing. They are tools for expression. They abide by some rules - often mathematical - but you can arrive at a &amp;ldquo;solution&amp;rdquo; in many different, creative, delightful ways. Reading code/music is harder, more onerous and less fun than writing it - than playing with it.&lt;/p>
&lt;p>So imagine a history of the music industry that had zero appreciation for music? But only criticized the ways rapacious capitalism has poisoned and perverted it? That - in a way - endorsed the &amp;ldquo;tech exceptionalist&amp;rdquo; narrative that tech is somehow &amp;ldquo;beyond [the] good and evil&amp;rdquo; of capitalism. No! Tech is not exceptional. And a history of music without any understanding of why some people enjoy making (or listening to) music is a very woeful perspective indeed. And its narrowness would be immediately apparent! But for whatever reason, coding&amp;rsquo;s bullshit public relations has ruined it in the cultural imagination to such a point that seeing accurate portrayals of the Joy of Coding, of the hacker spirit, are few and far between. (I have GREAT hopes for &lt;a href="https://www.goodreads.com/book/show/31450584-life-in-code?from_search=true&amp;from_srp=true&amp;qid=m7Aa7V6UzU&amp;rank=1">Ellen Ullman&amp;rsquo;s memoirs&lt;/a>.) Seriously, the only ones I can think of are Merlin in Disney&amp;rsquo;s The Sword in the Stone (he is a true tinkerer, people), &lt;a href="https://www.goodreads.com/book/show/23848323-dawn-of-the-new-everything?from_search=true&amp;from_srp=true&amp;qid=I3dH6DjqFO&amp;rank=6">Jaron Lanier&amp;rsquo;s memoir&lt;/a>, and, of course, almost anything by my beloved &lt;a href="https://www.goodreads.com/book/show/954674.Little_Brother?ac=1&amp;from_search=true&amp;qid=u2NXmDOQaj&amp;rank=3">Cory Doctorow&lt;/a>.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/45186565-uncanny-valley" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>LLM book recommender system</title><link>https://www.angelaambroz.com/posts/llm_book_recsys/</link><pubDate>Tue, 28 Oct 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/llm_book_recsys/</guid><description>&lt;p>I now have several different apps to organize my self-hosted media: &lt;a href="https://www.plex.tv/" target="_blank">Plex&lt;/a> for movies and TV, &lt;a href="https://www.audiobookshelf.org/" target="_blank">Audiobookshelf&lt;/a> for audiobooks, and &lt;a href="https://github.com/crocodilestick/Calibre-Web-Automated" target="_blank">Calibre-web-automated&lt;/a> for ebooks.&lt;/p>
&lt;h2 class="relative group">🎥 Discovery on Plex: really good
&lt;div id="-discovery-on-plex-really-good" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#-discovery-on-plex-really-good" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The UX on these apps is uniformly pretty good, with a few being great. Plex, for example, is a joy: the metadata is super well-organized, and so you can easily traverse your movie collection to find, e.g., all the Colin Firth movies you do and do not own (narrator: she owns enough). Similarly, it enriches your existing (probably paltry) metadata with, for example, IMDb and Rotten Tomato ratings, category, country of origin, etc. This is all super helpful for &lt;strong>discovery&lt;/strong> which - when you have a big media library - is key. You can use either deterministic rules (&amp;ldquo;sort all my unwatched Italian-language movies by audience rating&amp;rdquo;). And it includes, on every movie page, some &amp;ldquo;more like this&amp;rdquo; suggestions - probably powered, under the hood, by a reasonable &lt;a href="https://en.wikipedia.org/wiki/Recommender_system" target="_blank">recommender system (&amp;ldquo;recsys&amp;rdquo;)&lt;/a>.&lt;/p>
&lt;h2 class="relative group">🎧 Discovery on Audiobookshelf: also quite good
&lt;div id="-discovery-on-audiobookshelf-also-quite-good" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#-discovery-on-audiobookshelf-also-quite-good" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Audiobookshelf is probably next in terms of UX and discoverability: like Plex, it does a great job of organizing your media library&amp;rsquo;s metadata. It does &lt;em>not&lt;/em> have a built-in machine learning-powered recommender system, alas, but it &lt;em>does&lt;/em> have very good metadata matching. Each audiobook has a ton of rich tags and categories and so you can, at least, manually look things up by categorical vibe.&lt;/p>
&lt;h2 class="relative group">📚 Discovery on Calibre-web-automated: not so good
&lt;div id="-discovery-on-calibre-web-automated-not-so-good" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#-discovery-on-calibre-web-automated-not-so-good" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Which brings us to Calibre. Oh, Calibre. Salty, salt-o-the-earth Calibre. Calibre is dinosaur software, it&amp;rsquo;s been around forever and has a huge community. It has lots of quirks, both in its community, its development, and its user interface/UX. But it is, as they say, very powerful. Several attempts have been made to essentially re-skin Calibre into a slightly more modern-looking web interface: &lt;a href="https://github.com/janeczku/calibre-web" target="_blank">Calibre-web&lt;/a> being the main one I know about. A &lt;em>fork&lt;/em> of calibre-web is &lt;a href="https://github.com/crocodilestick/Calibre-Web-Automated" target="_blank">Calibre-Web-Automated&lt;/a> which&amp;hellip; well, to be honest, I&amp;rsquo;ve read the README.md tons of times and I still don&amp;rsquo;t see why I&amp;rsquo;m using it versus just calibre-web. But no matter. It has 3.5k stars on GitHub. They can&amp;rsquo;t all be wrong?!&lt;/p>
&lt;p>Anyway, one thing that Calibre(-web)(-automated) all lack is any sense of discovery. This is mostly because, weirdly (for such well-used and well-loved software!), the way they handle book metadata is kinda garbage? At least, when you add an ebook to your library, the flow is &lt;em>not&lt;/em> to immediately give you a best-match metadata chunk (as in Plex or Audiobookshelf). There&amp;rsquo;s &lt;em>tons&lt;/em> of UX love this app (these apps) need (e.g. I can&amp;rsquo;t click on multiple books unless I first switch to &amp;ldquo;Book list&amp;rdquo; mode? whyyyy?). But the big one that I need (NEED) is &lt;strong>decent discovery.&lt;/strong>&lt;/p>
&lt;h1 class="relative group">Using an LLM to do discovery on my own Calibre library
&lt;div id="using-an-llm-to-do-discovery-on-my-own-calibre-library" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#using-an-llm-to-do-discovery-on-my-own-calibre-library" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>I just finished &lt;a href="https://thecon.ai/" target="_blank">The AI Con&lt;/a> (5 stars, v good, highly recommend), and so I do hesitate to touch LLMs these days - especially due to the &lt;a href="https://news.mit.edu/2025/explained-generative-ai-environmental-impact-0117" target="_blank">water usage&lt;/a>. But, well, okay, this one&amp;rsquo;s pretty cool. Basically, in plain English:&lt;/p>
&lt;ol>
&lt;li>Get my Calibre &lt;code>metadata.db&lt;/code>, the sqlite3 database that stores all my book data (title, author, read/not read, description, tags&amp;hellip;), from my Calibre container.&lt;/li>
&lt;li>Add above &lt;code>.db&lt;/code> to my &lt;a href="https://www.angelaambroz.com/posts/marimo_notebooks">self-hosted Marimo container&lt;/a>.&lt;/li>
&lt;li>Launch a cool, new notebook called &lt;code>librarian.py&lt;/code>, hehehehe.&lt;/li>
&lt;li>Connect that notebook to the Anthropic API.&lt;/li>
&lt;li>&lt;code>pd.read_sql(&amp;quot;SELECT * FROM books&amp;quot;, con=conn)&lt;/code> from your &lt;code>metadata.db&lt;/code> and do some light cleaning (well, hopefully). I realized early on that I was just blowing money by feeding &lt;em>way&lt;/em> too much textual data about my ebook library. For now, I just send the title-author pairs of all unread books to Claude.&lt;/li>
&lt;li>Ask Claude to be my librarian!&lt;/li>
&lt;/ol>
&lt;p>Here&amp;rsquo;s my very exciting prompt and Anthropic API call:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_book_recs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mood&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">books_df&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">mood&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;No mood!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># create a context string from your books&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">book_context&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">books_df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_dict&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orient&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;records&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> You are a world-class librarian. You prioritize books from under-represented
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> groups (women, POC).
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Here are the books in my library (id, title, author):
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">book_context&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> I&amp;#39;m in the mood for: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">mood&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Please recommend books from this list that most match my mood. If you can&amp;#39;t
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> find any in my library, please point me to the most relevant books that I
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> can look for externally.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Please use Markdown formatting. Format every recommended book
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> with &amp;lt;a href=&amp;#34;http://my_super_cool_calibre_ip/book/id&amp;gt;title&amp;lt;/a&amp;gt;.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># hit your llm api here&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">messages&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;claude-sonnet-4-5-20250929&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_tokens&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>&lt;span class="s2">&amp;#34;role&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># parse response and filter df&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">message&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">TEST_PROMPT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;something solarpunk and light, &amp;lt;200 pages&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Your API call here&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">recommendations&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_book_recs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mood_input&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 class="relative group">Results
&lt;div id="results" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#results" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>So how does this perform? Honestly, pretty good!&lt;/p>
&lt;p>I&amp;rsquo;m basically pulling from Anthropic&amp;rsquo;s training data for any scraped data on my title-authors. This works great for relatively well-known (or, at least, well-represented-in-the-corpus) stuff. It struggles, of course, on anything very new or anything obscure. So the recommendations are always going to skew relatively well-known. But that&amp;rsquo;s okay! This has been a great discovery tool. I have about ~1k ebooks in my library - a mix of technical books (so many &lt;a href="https://www.humblebundle.com/books" target="_blank">Humble Bundles&lt;/a>, mamma mia), sci-fi, literary fiction, politics, history, economics. Sometimes I&amp;rsquo;ll be in the mood for a specific theme or type of book. Being able to &amp;ldquo;speak&amp;rdquo; to my library in natural language is great! And fun!&lt;/p>
&lt;h3 class="relative group">Example run
&lt;div id="example-run" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#example-run" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Here&amp;rsquo;s an example run I did just now.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/llm_book_recsys/2025-10-26_22-40_hua183b34726c85e0cce21f6221f6a957b_89766_330x0_resize_box_3.png 330w,
/posts/llm_book_recsys/2025-10-26_22-40_hua183b34726c85e0cce21f6221f6a957b_89766_660x0_resize_box_3.png 660w,
/posts/llm_book_recsys/2025-10-26_22-40_hua183b34726c85e0cce21f6221f6a957b_89766_1024x0_resize_box_3.png 1024w,
/posts/llm_book_recsys/2025-10-26_22-40_hua183b34726c85e0cce21f6221f6a957b_89766_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/llm_book_recsys/2025-10-26_22-40_hua183b34726c85e0cce21f6221f6a957b_89766_660x0_resize_box_3.png"
alt="screenshot of a marimo notebook"
/>
&lt;/figure>
&lt;/p>
&lt;p>Can you even see that? Sorry it&amp;rsquo;s so small. My request was, &amp;ldquo;what&amp;rsquo;s some good fiction to read about working in the tech industry?&amp;rdquo;&lt;/p>
&lt;p>The full response is pretty good:&lt;/p>
&lt;blockquote>
From Your Library:
&lt;p>Close to the Machine&lt;/p>
&lt;p>by Ellen Ullman This is a classic memoir/fiction hybrid about a software engineer in San Francisco during the first dot-com boom. Ullman brilliantly captures the isolation, obsession, and strange intimacy of coding work. It&amp;rsquo;s considered one of the best books ever written about what it actually feels like to work as a programmer.&lt;/p>
&lt;p>Uncanny Valley&lt;/p>
&lt;p>by Anna Wiener A memoir about working at various Silicon Valley startups during the 2010s tech boom. Wiener chronicles her transition from the literary world to tech with sharp, insightful observations about startup culture, gender dynamics, and the industry&amp;rsquo;s impact on society.&lt;/p>
&lt;p>Several People Are Typing&lt;/p>
&lt;p>by Calvin Kasulke A clever, experimental novel told entirely through Slack messages about a worker whose consciousness gets stuck in Slack. It&amp;rsquo;s a funny, surprisingly moving meditation on remote work culture and digital existence.&lt;/p>
&lt;p>Moonbound&lt;/p>
&lt;p>. by Robin Sloan While more fantastical, this book features tech industry elements and Sloan (who also wrote Mr. Penumbra&amp;rsquo;s 24-Hour Bookstore) has a background in tech and writes beautifully about digital culture.&lt;/p>
&lt;p>Other Books to Look For Externally:&lt;/p>
&lt;ul>
&lt;li>Microserfs by Douglas Coupland - A novel about Microsoft employees in the 90s&lt;/li>
&lt;li>The Circle by Dave Eggers - A dystopian take on a Google/Facebook-like company&lt;/li>
&lt;li>The Every by Dave Eggers - Sequel to The Circle&lt;/li>
&lt;li>Severance by Ling Ma - Combines office work dystopia with a pandemic narrative&lt;/li>
&lt;li>Qualityland by Marc-Uwe Kling - Satirical sci-fi about tech monopolies&lt;/li>
&lt;/ul>
&lt;/blockquote></description></item><item><title>Averting the Digital Dark Age - How Archivists, Librarians, and Technologists Built the Web a Memory - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/averting_the_digital_darkage/</link><pubDate>Sun, 14 Sep 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/averting_the_digital_darkage/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/averting_the_digital_darkage/book_jacket_hua7273b1cbc311ea21bd6781d8cbae773_28582_330x0_resize_q75_box.jpg 330w,
/posts/averting_the_digital_darkage/book_jacket_hua7273b1cbc311ea21bd6781d8cbae773_28582_660x0_resize_q75_box.jpg 660w,
/posts/averting_the_digital_darkage/book_jacket_hua7273b1cbc311ea21bd6781d8cbae773_28582_1024x0_resize_q75_box.jpg 1024w,
/posts/averting_the_digital_darkage/book_jacket_hua7273b1cbc311ea21bd6781d8cbae773_28582_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/averting_the_digital_darkage/book_jacket_hua7273b1cbc311ea21bd6781d8cbae773_28582_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Ian Milligan&lt;/li>
&lt;li>Number of pages: 208&lt;/li>
&lt;li>Year published: 2024&lt;/li>
&lt;li>Year read: 2025&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Note: Available for free on &lt;a href="https://muse.jhu.edu/book/123276">the publisher&amp;rsquo;s website&lt;/a>. I have no idea how I found this book (probably my self-hosted RSS feed or Mastodon or other nerd worlds) but I&amp;rsquo;m so glad I did.&lt;/p>
&lt;p>Pretty fabulous. This reads a bit like a very well-written PhD dissertation, or academic textbook. It&amp;rsquo;s a pretty niche topic - memory work (archiving) in the context of the World Wide Web - but it scratched a very specific itch I was having about my own data, scattered as it is among Big Tech&amp;rsquo;s platforms. The author actually notes this in the book&amp;rsquo;s conclusion: that the &amp;ldquo;digital dark age&amp;rdquo; remains a bogeyman for many in tech, even though the structures are now in place that it&amp;rsquo;s basically impossible (barring a &amp;ldquo;nondigital dark age&amp;rdquo; happening as well). The real risks, instead, are individual &amp;ldquo;dark ages&amp;rdquo;: e.g. Google Photos basically becoming your memory landlord that you rent the right to your pictures from. Horror of horrors!!!&lt;/p>
&lt;p>Anyway, this was a wonderfully rich history of the early web - we spend a lot of time in the 90s and early 00s. I love social histories of technology. SO MUCH. There are chapters on the Internet Archive and the various archival strategies used by different national libraries (Canada, Sweden, Australia, the US). Libraries are SO COOL. I&amp;rsquo;m excited to read more about this work. Anyway, the Internet Archive and these libraries are the spine of digital archiving - I learned a lot about Brewster Kahle and Heritrix and just, like, internet stuff. Early web stuff is so interesting. And a good reminder that we are still grappling with all the usual dramas, WHILE ALSO experiencing interesting changes (web 2.0! and now the totally justifiable and I am 100% on-board backlash against Big Tech). Who knew networking computers could be so interesting and such drama.&lt;/p>
&lt;p>Very similar to &lt;a href="https://www.goodreads.com/book/show/16718273-spam?ac=1&amp;from_search=true&amp;qid=N9buK4qM9l&amp;rank=5">Finn Brunton&amp;rsquo;s Spam&lt;/a>, another terrific book about internet stuff.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/208283384-averting-the-digital-dark-age" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>The AI Con - ⭐⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/the_ai_con/</link><pubDate>Sun, 14 Sep 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/the_ai_con/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/the_ai_con/book_jacket_hu80b554d29e0e26002eeada2150c11f1a_52995_330x0_resize_q75_box.jpg 330w,
/posts/the_ai_con/book_jacket_hu80b554d29e0e26002eeada2150c11f1a_52995_660x0_resize_q75_box.jpg 660w,
/posts/the_ai_con/book_jacket_hu80b554d29e0e26002eeada2150c11f1a_52995_1024x0_resize_q75_box.jpg 1024w,
/posts/the_ai_con/book_jacket_hu80b554d29e0e26002eeada2150c11f1a_52995_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/the_ai_con/book_jacket_hu80b554d29e0e26002eeada2150c11f1a_52995_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Emily Bender, Alex Hanna&lt;/li>
&lt;li>Number of pages: 288&lt;/li>
&lt;li>Year published: 2025&lt;/li>
&lt;li>Year read: 2025&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>As &lt;a href="https://www.goodreads.com/book/show/28186015-weapons-of-math-destruction?ac=1&amp;from_search=true&amp;qid=5DddcBR2J4&amp;rank=1">Weapons of Math Destruction&lt;/a> was to the 2010s and basic machine learning, so this book is to the 2020s and &amp;ldquo;AI&amp;rdquo;.&lt;/p>
&lt;p>So: I loved this book. It set my head straight on a lot of things I intuitively knew, as someone with enough expertise to understand how the &amp;ldquo;AI&amp;rdquo; sausages are being made, but was struggling to articulate. And hype is strong! We are social apes! Like - yes - natural language processing (NLP) is amazing and gratifying and weird. (Text is such gnarly data!) But NLP has been eerily amazing for a long while now (I have felt the icy showers for at least 10 years! &lt;a href="https://en.wikipedia.org/wiki/Tf%E2%80%93idf">tf-idf&lt;/a>?! whaaat!?), and these &lt;a href="https://en.wikipedia.org/wiki/Stochastic_parrot">stochastic parrots&lt;/a> are indeed eerily amazing as well. But! Do they deserve all this hype? Where by &amp;ldquo;hype&amp;rdquo;, the authors specifically mean: enormous venture capital investments, enormous carbon emissions and re-jiggering of our energy infrastructure, and - perhaps worst of all? - figures of authority waving their arms around a vaguely-defined but definitely civilization-altering &amp;ldquo;Artificial General Intelligence (AGI)&amp;rdquo; that is always just beyond the horizon?&lt;/p>
&lt;p>The authors argue - aggressively, spicily, wonderfully - that NO! This is all bananas! And I am 100% here for it.&lt;/p>
&lt;p>First, they give one of the best plain English primers on neural networks, n-grams, and &lt;a href="https://en.wikipedia.org/wiki/Embedding_%28machine_learning%29">embeddings&lt;/a>. It&amp;rsquo;s one chapter, and it&amp;rsquo;s only semi-technical (intended for non-technical audiences), but it covers, imo, the main ideas in a very clear, comprehensive way. So bravi, there! They also offer refreshing clarity on defining &amp;ldquo;AI&amp;rdquo; - a term that is, currently, being abused in everyday conversation, but that normally captures distinct fields in machine learning/comp sci: large language models (LLMs), &lt;a href="https://en.wikipedia.org/wiki/Optical_character_recognition">OCR&lt;/a>, &lt;a href="https://en.wikipedia.org/wiki/Computer_vision">computer vision&lt;/a>, blah blah, I am tired of linking.&lt;/p>
&lt;p>Rather than prognosticating about the future (and, indeed, notice how much AI hype is about the very near future&amp;hellip; it&amp;rsquo;s just over the horizon, people!), they instead trace the history of AI (leveling some shots at Minsky and Hinton, wowza), the history of Luddites, and the CURRENT practices of how LLMs are trained, how they are used RIGHT NOW, and how they are talked about. There is a lot about labor (outsourced content moderation is horrible indeed; your boss being sold AI to &amp;ldquo;boost productivity&amp;rdquo; == aka, layoffs) and training data bias (duh) and basically plugging the holes in our social safety net with word-prediction machines. All of this was stuff I knew, but they structured it in a clear and helpful way.&lt;/p>
&lt;p>The one thing I did NOT know, but blew my mind, was the theory of mind stuff and linguistics (Emily Bender is a linguistics prof at U of Washington). Basically, language includes a lot of &amp;ldquo;guessing what the other person is thinking/trying to say&amp;rdquo;. That&amp;rsquo;s why you can&amp;rsquo;t teach your baby Italian via TV (believe me, I&amp;rsquo;ve tried). It&amp;rsquo;s the &lt;em>interaction&lt;/em> that matters. The social learning. Because LLMs are so good at sounding human, our brains naturally start to &amp;ldquo;fill in the blanks&amp;rdquo; about what they&amp;rsquo;re &amp;ldquo;thinking/trying to say&amp;rdquo;. This is also why people DO NOT ascribe cognition to &amp;ldquo;AI artists&amp;rdquo; when they look at those (frankly very tacky) DALL-E, Midjourney, genAI art outputs. No one thinks an &amp;ldquo;AI&amp;rdquo; was trying to &amp;ldquo;express its consciousness&amp;rdquo; - we see it as an obviously computer-generated, automated mish-mash of training inputs. But LANGUAGE. Our ape brains get real weird there. Hence all the flailing around &amp;ldquo;omg AGIIIII&amp;rdquo;.&lt;/p>
&lt;p>Anyway, I loved this so much. Should be required reading for everyone in tech.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/217432753-the-ai-con" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Hosting my own notebook server</title><link>https://www.angelaambroz.com/posts/marimo_notebooks/</link><pubDate>Tue, 26 Aug 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/marimo_notebooks/</guid><description>&lt;p>Like many a data scientist, I&amp;rsquo;ve spent tons of time in &lt;a href="https://jupyter.org/" target="_blank">Jupyter&lt;/a> notebooks. For many years (2015-2022), I mostly just used vanilla Jupyter - or sometimes Google Colab. In 2023, we started using &lt;a href="https://hex.tech/" target="_blank">Hex&lt;/a> at work, which was super slick and fun: LLM-powered cells! Dark mode! Cells that remember each other&amp;rsquo;s state!&lt;/p>
&lt;p>I&amp;rsquo;ve been, indeed, very happy with Hex for these last couple years. But, in my &lt;a href="https://angelaambroz.com/posts/homelab_overview/" target="_blank">homelab journey&lt;/a>, I realized having a notebook environment to explore my data - my transaction history from Mint, my purchase history from Amazon, my &lt;a href="https://angelaambroz.com/posts/job_hunt_2022/" target="_blank">job hunt data&lt;/a> - would be really cool. This became even cooler as I stood up services with database backends - my audiobooks! my ebooks! - the possibilities for data analytics on my own data were endless!&lt;/p>
&lt;p>At first, I just set up the basic &lt;a href="https://hub.docker.com/r/jupyter/datascience-notebook/" target="_blank">data science Jupyter notebook&lt;/a> via Docker Hub. I used it for a few days but it felt very, well, 2015. I was like, come on, there &lt;em>must&lt;/em> be something slicker out there!&lt;/p>
&lt;h1 class="relative group">Enter &lt;a href="https://marimo.io/" target="_blank">marimo&lt;/a>!
&lt;div id="enter-marimohttpsmarimoio" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#enter-marimohttpsmarimoio" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>I did a bit of research (&lt;a href="https://kagi.com/" target="_blank">Kagi&lt;/a>-ing, LLMing), and landed on &lt;a href="https://marimo.io/" target="_blank">marimo&lt;/a>. It was tons of good things: &lt;a href="https://github.com/marimo-team/marimo" target="_blank">open-source&lt;/a>, &lt;a href="https://docs.marimo.io/guides/deploying/deploying_docker/?h=docker" target="_blank">self-hostable&lt;/a>, with &lt;a href="https://docs.marimo.io/guides/editor_features/ai_completion/?h=llm#connecting-to-an-llm" target="_blank">flexible AI integration&lt;/a> - including using a &lt;a href="https://angelaambroz.com/posts/local_ai_setup/" target="_blank">self-hosted LLM backend&lt;/a>. Also: dark mode! Turning things into apps! Notebooks getting automatically turned into version-controllable Python &lt;code>.py&lt;/code> files! Per-notebook environment management with &lt;a href="https://docs.marimo.io/guides/package_management/" target="_blank">uv&lt;/a>!&lt;/p>
&lt;p>That&amp;rsquo;s it! Glorious.&lt;/p></description></item><item><title>Homelab overview</title><link>https://www.angelaambroz.com/posts/homelab_overview/</link><pubDate>Fri, 01 Aug 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/homelab_overview/</guid><description>&lt;p>&lt;em>Updated: 5 Dec 2025&lt;/em>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>thing&lt;/th>
&lt;th>service&lt;/th>
&lt;th>replaces&lt;/th>
&lt;th>phone?&lt;/th>
&lt;th>ereader?&lt;/th>
&lt;th>rating&lt;/th>
&lt;th>thoughts&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Movies, TV&lt;/td>
&lt;td>&lt;a href="https://www.plex.tv/" target="_blank">Plex&lt;/a>&lt;/td>
&lt;td>Netflix, all the various streaming services&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>n/a&lt;/td>
&lt;td>⭐⭐⭐⭐&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Ebooks&lt;/td>
&lt;td>&lt;a href="https://github.com/crocodilestick/Calibre-Web-Automated" target="_blank">Calibre-Web-Automated&lt;/a>&lt;/td>
&lt;td>Amazon&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>⭐⭐⭐&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Audiobooks&lt;/td>
&lt;td>&lt;a href="https://www.audiobookshelf.org/" target="_blank">Audiobookshelf&lt;/a>&lt;/td>
&lt;td>Amazon&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>n/a&lt;/td>
&lt;td>⭐⭐⭐⭐&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>News/blogs/social media&lt;/td>
&lt;td>&lt;a href="https://freshrss.org/" target="_blank">FreshRSS&lt;/a>&lt;/td>
&lt;td>Twitter, Facebook, NYT&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>haven&amp;rsquo;t tried yet, but theoretically yes?&lt;/td>
&lt;td>⭐⭐⭐⭐&lt;/td>
&lt;td>&lt;a href="https://www.angelaambroz.com/posts/one_true_rss/">Moving everything to RSS&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Bookmarks/read it later&lt;/td>
&lt;td>&lt;del>&lt;a href="https://github.com/wallabag/wallabag?tab=readme-ov-file" target="_blank">Wallabag&lt;/a>&lt;/del> &lt;a href="https://readeck.org/en/" target="_blank">Readeck&lt;/a>&lt;/td>
&lt;td>Pocket&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>⭐⭐⭐&lt;/td>
&lt;td>&lt;del>&lt;a href="https://www.angelaambroz.com/posts/selfhosted_read_it_later/">Reading things later with Wallabag and my Kobo&lt;/a>&lt;/del> &lt;a href="https://www.angelaambroz.com/posts/readeck">Migrating from Wallabag to Readeck&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Syncing&lt;/td>
&lt;td>&lt;a href="https://syncthing.net/" target="_blank">Syncthing&lt;/a>&lt;/td>
&lt;td>Dropbox, Google Drive&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>❌&lt;/td>
&lt;td>⭐⭐⭐&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Notes&lt;/td>
&lt;td>&lt;a href="https://obsidian.md/" target="_blank">Obsidian&lt;/a>&lt;/td>
&lt;td>Evernote&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>n/a&lt;/td>
&lt;td>⭐⭐⭐&lt;/td>
&lt;td>&lt;a href="https://angelaambroz.com/posts/obsidian/" target="_blank">On being an Obsidian power user&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Document digitization&lt;/td>
&lt;td>&lt;a href="https://docs.paperless-ngx.com/" target="_blank">Paperless-ngx&lt;/a>&lt;/td>
&lt;td>Dropbox&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>n/a&lt;/td>
&lt;td>⭐⭐⭐⭐&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Photos&lt;/td>
&lt;td>&lt;a href="https://immich.app/" target="_blank">Immich&lt;/a>&lt;/td>
&lt;td>Google Photos&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>n/a&lt;/td>
&lt;td>⭐⭐⭐⭐&lt;/td>
&lt;td>&lt;a href="https://www.angelaambroz.com/posts/google_takeout_sucks/">Imprisoning your users - an experience with Google Takeout&lt;/a>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Those are all the services I have so far, and they are making my poor little Synology NAS choke and wheeze. Sorry, buddy. Yet while my Synology suffers, I am filled with joy!&lt;/p>
&lt;p>I still have a few pieces I&amp;rsquo;d like to put together, to really bring this &amp;ldquo;self-hosted Internet&amp;rdquo; thing home (nyuk nyuk nyuk):&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Cooking?&lt;/strong> NYT Cooking is still my go-to for excellent recipes (and comment banter), and &lt;a href="https://www.eatyourbooks.com/" target="_blank">Eat Your Books&lt;/a> is awesome for indexing my existing, physical cookbooks. I&amp;rsquo;ve seen some self-hostable FOSS options like &lt;a href="https://mealie.io/" target="_blank">Mealie&lt;/a>, &lt;a href="https://tandoor.dev/" target="_blank">Tandoor&lt;/a>, maybe kinda &lt;a href="https://grocy.info/" target="_blank">Grocy&lt;/a>? None of them are really inspiring me yet - and Tandoor made my Synology &lt;em>really&lt;/em> struggle - but we&amp;rsquo;ll see.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Passwords?&lt;/strong> I&amp;rsquo;m comforted by the idea of locally hosting my password manager - it did always feel a bit weird to have my One Password to Rule Them All chilling in the cloud somewhere (encrypted or not idk).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Git?&lt;/strong> Another sort of interesting one. I hadn&amp;rsquo;t considered self-hosting a GitHub replacement. As &lt;a href="https://press.stripe.com/working-in-public" target="_blank">Working in Public&lt;/a> discussed, a lot of the open source ecosystem is platformed by GitHub - and kind of incentivized/promoted/facilitated by GitHub and its &amp;ldquo;social media&amp;rdquo;-esque features. I do have some private git repos - e.g. my family holiday card - that I use GitHub to version control and&amp;hellip; well, I don&amp;rsquo;t like doing that. I would prefer something more private for those.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>LLMs!&lt;/strong> This is the big one. I use Claude so much these days and would LOVE a truly private, local, self-hosted LLM option. It&amp;rsquo;s only a matter of time before Claude/ChatGPT/etc start promoting products, and I want to get out and have my own local solution before then. I&amp;rsquo;ve played around with &lt;a href="https://openwebui.com/" target="_blank">Open Web UI&lt;/a> and &lt;a href="https://ollama.com/" target="_blank">Ollama&lt;/a> - just on my wheezing, middle-aged &lt;a href="https://system76.com/laptops/lemp13/configure" target="_blank">Lemur Pro&lt;/a> and just as a proof of concept. It worked! Huzzah. But there&amp;rsquo;s no way my Synology could handle the compute that even a small model would need. So I&amp;rsquo;m daydreaming about upgrading my hardware to a GPU and &lt;em>really&lt;/em> getting things going&amp;hellip; &lt;strong>Update, Aug 2025&lt;/strong>: I&amp;rsquo;m now halfway there with a &lt;a href="https://angelaambroz.com/posts/local_ai_setup/" target="_blank">local pass-through of cloud LLM providers&lt;/a>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Video calls?&lt;/strong> &lt;a href="https://fossacademic.tech/" target="_blank">FOSS Academic&lt;/a> had a cool post about using only, well, FOSS tools - including &lt;a href="https://nextcloud.com/" target="_blank">Nextcloud&lt;/a> for video conferencing. I also want to support digital sovereingty/European tech for political reasons - and Nextcloud is French? German? Frerman. I also kinda wonder if I can get my non-tech fam onto Nextcloud? I&amp;rsquo;ve discovered one of them is paying for Dropbox again. 😬&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Minecraft?&lt;/strong> My kids are actually still too small for Minecraft, but, well, it&amp;rsquo;s an option. Any other games? I would love to self-host some of my nostalgia games of yore like &lt;a href="https://sega-play.online/earthworm-jim" target="_blank">Earthworm Jim&lt;/a> or &lt;a href="https://en.wikipedia.org/wiki/The_Sims_%28video_game%29" target="_blank">The Sims&lt;/a>.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>I also have been thinking about switching out some of these services - e.g. &lt;a href="https://karakeep.app/" target="_blank">Karakeep&lt;/a> for Wallabag? &lt;a href="https://jellyfin.org/" target="_blank">Jellyfin&lt;/a> for Plex? 🤷 For now, I&amp;rsquo;m (very) happy.&lt;/p>
&lt;h3 class="relative group">Some &amp;ldquo;economics of open source&amp;rdquo; thoughts
&lt;div id="some-economics-of-open-source-thoughts" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#some-economics-of-open-source-thoughts" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>&lt;a href="https://press.stripe.com/working-in-public" target="_blank">Working in Public&lt;/a> was a starter book on economics in open source - but it really just scratched the surface, tbh. I was trained as an economist - it was my first love! 💙 - and I get easily nerd sniped by odd socio-economic arrangements. And open source is odd! It is weird and wonderful! The idea that people bring their technical skills to voluntarily work on hobby projects collaboratively&amp;hellip; For no reason except passion???&amp;hellip; And that those projects end up, uh, supporting the entire Internet infrastructure (I&amp;rsquo;m thinking of &lt;a href="https://en.wikipedia.org/wiki/Linux" target="_blank">Linux&lt;/a> and &lt;a href="https://en.wikipedia.org/wiki/Git" target="_blank">git&lt;/a> and &lt;a href="https://en.wikipedia.org/wiki/Python_%28programming_language%29" target="_blank">Python&lt;/a> and &lt;a href="https://pandas.pydata.org/" target="_blank">pandas&lt;/a>&amp;hellip;). Last I checked, the market cap for &lt;a href="https://finance.yahoo.com/sectors/technology/?guccounter=1" target="_blank">&amp;ldquo;tech&amp;rdquo; is ~20 trillion USD&lt;/a>. And - again - the absolute core foundation is&amp;hellip; based on free labor? Driven by passion?&lt;/p>
&lt;p>What&amp;rsquo;s even more exciting (and anarchic&amp;hellip;) about open source is that it can only be successful if it&amp;rsquo;s &lt;em>collaborative&lt;/em>. One of the big themes of &lt;a href="https://us.pycon.org/2025/" target="_blank">PyCon this year&lt;/a> (beyond &lt;a href="https://www.youtube.com/watch?v=ydVmzg_SJLw" target="_blank">politics!&lt;/a>) was actually &lt;strong>maintainer burnout&lt;/strong> - see Lynn Root&amp;rsquo;s &lt;a href="https://www.youtube.com/watch?v=ydVmzg_SJLw" target="_blank">keynote about this&lt;/a>. Burnout permeated tons of discussions and talks. And, indeed, Working in Public highlighted how many (many many&amp;hellip;) open source projects often rely on a single (!) maintainer - doing frankly thankless grunt work to keep it going.&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://imgs.xkcd.com/comics/dependency.png" alt="xkcd" />
&lt;/figure>
&lt;/p>
&lt;p>I remember running into that when I made a PR, long ago (maybe for Hacktober?), on some Python timezone stuff. It may have been &lt;a href="https://github.com/stub42/pytz" target="_blank">pytz&lt;/a>. Something that was used&amp;hellip; everywhere?? I think I was fixing something in &lt;a href="https://github.com/psf/black" target="_blank">black&lt;/a>? Or pandas? Anyway, it was like a foundational library - the management of TIME - and it&amp;rsquo;s basically one guy who&amp;rsquo;s been maintaining it since forever.&lt;/p>
&lt;p>ALL THAT TO SAY&amp;hellip; these days, I think a lot about digital sovereignty and self-hosting and &lt;a href="https://www.youtube.com/watch?v=R7qT-C-0ajI" target="_blank">&amp;ldquo;well, we don&amp;rsquo;t have a lord&amp;rdquo;&lt;/a> and community building and human cooperation as the key to our survival. And I&amp;rsquo;m like, shit, I need to probably &lt;em>actively maintain&lt;/em> these services I&amp;rsquo;ve just installed from Docker Hub? Like, &lt;a href="https://www.audiobookshelf.org/" target="_blank">Audiobookshelf&lt;/a> is fantastic - but is it gonna be around in 1 year? 5 years? Do I need to help it? Will I eventually need to fork it and run my own? Should I fork it now and start specializing it to my very specific, tiny community&amp;rsquo;s needs? For now I am WAY too busy with &lt;a href="https://www.goodreads.com/book/show/414923.Counting_for_Nothing" target="_blank">paid tech job work and unpaid &amp;ldquo;women&amp;rsquo;s work&amp;rdquo;&lt;/a> (aka, the house and kids, aka maybe a big reason women&amp;rsquo;s contributions to FOSS are &lt;a href="https://biancatrink.github.io/files/papers/TOSEM2021.pdf" target="_blank">very rare indeed&lt;/a>).&lt;/p>
&lt;p>&lt;strong>Edited to add&lt;/strong>: Oh, funny, &lt;a href="https://www.shareable.net/systems-are-breaking-and-thats-our-opportunity/" target="_blank">a very relevant article on these issues just popped up in Shareable&lt;/a>.&lt;/p></description></item><item><title>Imprisoning your users - an experience with Google Takeout</title><link>https://www.angelaambroz.com/posts/google_takeout_sucks/</link><pubDate>Mon, 28 Jul 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/google_takeout_sucks/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/google_takeout_sucks/DSC_1061_hubfd2270494f9b8ee965bd96a3496cb28_600995_330x0_resize_q75_box.JPG 330w,
/posts/google_takeout_sucks/DSC_1061_hubfd2270494f9b8ee965bd96a3496cb28_600995_660x0_resize_q75_box.JPG 660w,
/posts/google_takeout_sucks/DSC_1061_hubfd2270494f9b8ee965bd96a3496cb28_600995_1024x0_resize_q75_box.JPG 1024w,
/posts/google_takeout_sucks/DSC_1061_hubfd2270494f9b8ee965bd96a3496cb28_600995_1320x0_resize_q75_box.JPG 2x"
src="https://www.angelaambroz.com/posts/google_takeout_sucks/DSC_1061_hubfd2270494f9b8ee965bd96a3496cb28_600995_660x0_resize_q75_box.JPG"
alt="terracotta rooftops in northern Italy"
/>
&lt;/figure>
&lt;/p>
&lt;p>For about 30 years, my grandmother used the same hole-in-the-wall shop to get her photos developed. She loved taking pictures of her paintings, sunsets, flowers, her family, and trips. Every few weeks, she would drop off a roll of film. The shop would do that darkroom chemistry stuff and deliver back to her a couple dozen photos, usually in a little, branded album. We have many of those albums lying around the house.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/google_takeout_sucks/DSC_0579_hue6ccd02ff44d0d88c1e45f31dabeb89e_399409_330x0_resize_q75_box.JPG 330w,
/posts/google_takeout_sucks/DSC_0579_hue6ccd02ff44d0d88c1e45f31dabeb89e_399409_660x0_resize_q75_box.JPG 660w,
/posts/google_takeout_sucks/DSC_0579_hue6ccd02ff44d0d88c1e45f31dabeb89e_399409_1024x0_resize_q75_box.JPG 1024w,
/posts/google_takeout_sucks/DSC_0579_hue6ccd02ff44d0d88c1e45f31dabeb89e_399409_1320x0_resize_q75_box.JPG 2x"
src="https://www.angelaambroz.com/posts/google_takeout_sucks/DSC_0579_hue6ccd02ff44d0d88c1e45f31dabeb89e_399409_660x0_resize_q75_box.JPG"
alt="a bowl of figs and apricots"
/>
&lt;/figure>
&lt;/p>
&lt;p>Fast forward to 2025. I&amp;rsquo;m very similar to my grandmother: I like to take pictures of flowers, my art, my knitted objects, my family and my trips. I put them in &lt;em>my&lt;/em> &lt;a href="https://en.wikipedia.org/wiki/Google_Photos" target="_blank">photo shop&lt;/a>. My shop doesn&amp;rsquo;t give me the photos - there&amp;rsquo;s far too many of them for me to keep at home, they assure me, but if I pay them a reasonable annual fee, they&amp;rsquo;ll hold them for me indefinitely. Additionally, I can pop into the shop at any time to look at them. The shop also sometimes sends me cute assortments of my photos, with cheesy background music, especially around the holidays. I do really enjoy this, except when they sometimes callously show me a rosey birthday video of a dead loved one. I need to remind them to please skip those photos from the sentimental collages.&lt;/p>
&lt;p>Behind the scenes, the shop uses my photos for some very cool, very advanced computer science projects. I notice that my photos start to get automatically labeled - they can tell it&amp;rsquo;s a picture of me from the 1990s, wow. I didn&amp;rsquo;t realize my photos were grist for this machine learning mill; it was probably buried in a &amp;ldquo;consent&amp;rdquo; form that didn&amp;rsquo;t actually gather consent in the typical meaning of the word. Anyway, I definitely learn about this after the fact. And I&amp;rsquo;m not thrilled about my family pics being used for science projects, but I guess the shop is good about privacy? &lt;a href="https://en.wikipedia.org/wiki/Privacy_concerns_with_Google" target="_blank">Right&lt;/a>??? Plus, it is amazing to be able to ask the robot shopkeeper for all pictures featuring one of my kids and a guitar. Wow, this robot is really smart! I do feel a bit uneasy that I don&amp;rsquo;t actually, physically have a copy of any of my family&amp;rsquo;s photos from the past 10 years but well hmm&amp;hellip;&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/google_takeout_sucks/DSC_0122_huf8dad76ba39640862d1159f52d9eecc0_649728_330x0_resize_q75_box.JPG 330w,
/posts/google_takeout_sucks/DSC_0122_huf8dad76ba39640862d1159f52d9eecc0_649728_660x0_resize_q75_box.JPG 660w,
/posts/google_takeout_sucks/DSC_0122_huf8dad76ba39640862d1159f52d9eecc0_649728_1024x0_resize_q75_box.JPG 1024w,
/posts/google_takeout_sucks/DSC_0122_huf8dad76ba39640862d1159f52d9eecc0_649728_1320x0_resize_q75_box.JPG 2x"
src="https://www.angelaambroz.com/posts/google_takeout_sucks/DSC_0122_huf8dad76ba39640862d1159f52d9eecc0_649728_660x0_resize_q75_box.JPG"
alt="black and white photo of graffiti"
/>
&lt;/figure>
&lt;/p>
&lt;p>Meanwhile, I read a &lt;a href="https://nextcloud.com/blog/nyt-reports-google-offers-no-recourse-for-mistakenly-blocked-accounts-even-in-egregious-cases/" target="_blank">scary article&lt;/a> about a time the shop locked its doors to a customer because they misunderstood one of the customer&amp;rsquo;s photos as being pornographic (it was medical). The customer was kicked out - and he wasn&amp;rsquo;t allowed to have any of his photos. My unease increases. Years pass.&lt;/p>
&lt;p>One day, I decide I&amp;rsquo;d like to take &lt;em>all&lt;/em> my photos out of the shop. Would this be possible, please? I&amp;rsquo;m tired of paying the shop the annual fee to house all my photos. I&amp;rsquo;m worried about having all my precious memory-eggs in one basket. I have a surgery coming up and need to take gnarly medical pictures and I don&amp;rsquo;t want to get banned! So I&amp;rsquo;d like to try another shop, please. This shop - very high-tech, maybe the highest-tech shop in the whole world - this shop that can make computers recognize my baby pics as &lt;em>me&lt;/em>, using only pictures of adult-me - has only ONE way to deliver photos. No, sorry, you can&amp;rsquo;t access the photos programmatically using an API - despite the abundance of APIs in the backroom.&lt;/p>
&lt;p>Here&amp;rsquo;s how I&amp;rsquo;m allowed to get my photos:&lt;/p>
&lt;ol>
&lt;li>I have to enter a &lt;em>different shop&lt;/em> and tell them I want the photo place&amp;rsquo;s photos. &amp;ldquo;Ugh, fine. We&amp;rsquo;ll let you know when it&amp;rsquo;s ready at some indeterminate time in the future.&amp;rdquo;&lt;/li>
&lt;li>I wait.&lt;/li>
&lt;li>Finally, my photos are ready to be picked up. The shop warns me: &amp;ldquo;if you don&amp;rsquo;t pick these up this week, we&amp;rsquo;re going to need a fresh request!&amp;rdquo; I am deeply annoyed at this Kafka-esque runaround.&lt;/li>
&lt;li>I go back to the different shop, Takeout, to pick up my photos. My photos are bundled together in 50GB .zip files that I need to, one by one, laboriously remove from the shop and heave into my tiny cart, before wheeling it to my slightly larger pickup truck.&lt;/li>
&lt;li>I have 7 of these bundles. It takes about one hour to get one of these .zip bundles from the shop into my pickup truck. I&amp;rsquo;m something of a &lt;a href="https://en.wikipedia.org/wiki/Home_server" target="_blank">pickup truck mechanic/hobbyist&lt;/a>, so I know how to do all this. But most of my normie, non-mechanic friends don&amp;rsquo;t really have anywhere to load their giant bundles; they just pay the fee and let the shops keep their photos and hope for the best.&lt;/li>
&lt;li>Also, by the way, every time I enter the shop - I need to show them my ID. Not my usual ID (a chocolate chip cookie they stuffed into my backpack on the way out), no. They want to see a key, as well as my second, plan B, just in case key. Man, they are surly, these types!&lt;/li>
&lt;li>Once I get all my stacked cartons of photos back at my house, I start to look through them. The organization is wild! Photo labels are spread out across different boxes, photos that I had meticulously organized into albums when I visited the shop have been re-shuffled in a seemingly random order. This is 10 years of my life, in photographs, and the metadata is just fucked. I am exhausted by the sight of it. It feels vindictive. Frickin&amp;rsquo; shop!!!&lt;/li>
&lt;/ol>
&lt;p>Yeah. So that was my experience with getting 300GB+ of photos out of Google Photos. After several aborted attempts, over several years (!).&lt;/p>
&lt;p>It&amp;rsquo;s amazing - galling, really! - how we&amp;rsquo;ve let this Big Tech monopoly get out of hand. And how completely turned around the notions of &amp;ldquo;user&amp;rdquo;, &amp;ldquo;customer&amp;rdquo;, and &amp;ldquo;company&amp;rdquo; have become. Why am I &lt;em>renting&lt;/em> my own memories back from a cloud landlord? Like a &lt;a href="https://archive.ph/0jAdi" target="_blank">digital serf&lt;/a>? Why are my photos being held hostage for shareholder value? Like, what are we even valuing? The photo of my grandmother is priceless to me - but it&amp;rsquo;s just one more data point to Google. The way we&amp;rsquo;ve structured tech into our lives is really crazy-making. Imagine what we could do if we didn&amp;rsquo;t prioritize the corporations&amp;rsquo; interests, but our own?&lt;/p>
&lt;p>Anyway&amp;hellip; Yeah, I&amp;rsquo;m not into it anymore. My data is mine! ✊ Once I get these sorted (&lt;em>thank you&lt;/em>, &lt;a href="https://github.com/simulot/immich-go" target="_blank">open source&lt;/a>) - programmatically! &lt;em>sanely!&lt;/em> - and running on &lt;a href="https://immich.app/" target="_blank">Immich&lt;/a> or &lt;a href="https://www.synology.com/en-global/dsm/feature/photos" target="_blank">Synology Photos&lt;/a> or just, like, my hard drive and an offsite backup, I will be VERY excited to delete them from Google&amp;rsquo;s servers. Wish me luck on the sorting-out part - I embark on that with dread.&lt;/p></description></item><item><title>Getting ready for local AI</title><link>https://www.angelaambroz.com/posts/local_ai_setup/</link><pubDate>Wed, 16 Jul 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/local_ai_setup/</guid><description>&lt;p>I mentioned in my &lt;a href="https://angelaambroz.com/posts/homelab_overview/" target="_blank">homelab post&lt;/a> that one of my STILL-TO-DOs was self-hosting LLMs. Unfortunately, we run into immediate hardware constraints on that one - I don&amp;rsquo;t have a single GPU lying around! Sad.&lt;/p>
&lt;p>I was ready to put this dream to rest, but &lt;a href="https://www.youtube.com/watch?v=nQCOTzS5oU0" target="_blank">a video by YouTuber NetworkChuck&lt;/a> was super interesting and inspiring. Basically, the idea is:&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/local_ai_setup/drawing1_hu787f02d66b51a918b1dcaf0839c54d0d_101664_330x0_resize_box_3.png 330w,
/posts/local_ai_setup/drawing1_hu787f02d66b51a918b1dcaf0839c54d0d_101664_660x0_resize_box_3.png 660w,
/posts/local_ai_setup/drawing1_hu787f02d66b51a918b1dcaf0839c54d0d_101664_1024x0_resize_box_3.png 1024w,
/posts/local_ai_setup/drawing1_hu787f02d66b51a918b1dcaf0839c54d0d_101664_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/local_ai_setup/drawing1_hu787f02d66b51a918b1dcaf0839c54d0d_101664_660x0_resize_box_3.png"
alt="a diagram of self-hosted AI UI"
/>
&lt;/figure>
&lt;/p>
&lt;p>In other words, I&amp;rsquo;m currently using my NAS as a &lt;strong>pass-through for any/all LLM work&lt;/strong>. I&amp;rsquo;m using &lt;a href="https://openwebui.com/" target="_blank">OpenWebUI&lt;/a> (interface), &lt;a href="https://ollama.com/" target="_blank">Ollama&lt;/a> (local LLMs), and &lt;a href="https://www.litellm.ai/" target="_blank">LiteLLM&lt;/a> (proxy/API connector). I&amp;rsquo;m connecting to Anthropic and OpenAI 🤮 using their APIs, and I have - for now - &lt;em>one&lt;/em> local LLM installed on the NAS (Mistral 7B). In some future world, I&amp;rsquo;ll spend the big bucks to get a GPU machine - maybe&amp;hellip; dare I dream&amp;hellip; a bedazzled &lt;a href="https://frame.work/desktop" target="_blank">Framework desktop&lt;/a>??&lt;/p>
&lt;p>Anyway. Why do this now? Pre-GPU?&lt;/p>
&lt;p>The basic idea I&amp;rsquo;ve been having is, I want my cyber&amp;lt;&amp;gt;meatspace interactions to be represented like this:
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/local_ai_setup/drawing2_huf1be6ca897cac46c290f52469bdc6280_81084_330x0_resize_box_3.png 330w,
/posts/local_ai_setup/drawing2_huf1be6ca897cac46c290f52469bdc6280_81084_660x0_resize_box_3.png 660w,
/posts/local_ai_setup/drawing2_huf1be6ca897cac46c290f52469bdc6280_81084_1024x0_resize_box_3.png 1024w,
/posts/local_ai_setup/drawing2_huf1be6ca897cac46c290f52469bdc6280_81084_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/local_ai_setup/drawing2_huf1be6ca897cac46c290f52469bdc6280_81084_660x0_resize_box_3.png"
alt="a diagram of a digital self (data), a UI, and a meatspace self"
/>
&lt;/figure>
That is:&lt;/p>
&lt;ul>
&lt;li>My meatspace self (and my friends, family, strangers, employers, etc)&lt;/li>
&lt;li>&amp;hellip;Interact with some UI&amp;hellip;&lt;/li>
&lt;li>&amp;hellip;To see my data/digital self&amp;hellip; &lt;em>which I still own and have control over&lt;/em>&lt;/li>
&lt;/ul>
&lt;p>If a UI breaks, changes, enshittifies, etc, I can just switch it out. This speaks to Cory Doctorow&amp;rsquo;s &lt;a href="https://spectrum.ieee.org/doctorow-interoperability" target="_blank">interopability dreams&lt;/a>. And yes, it&amp;rsquo;s all about tearing down the &lt;a href="https://en.wikipedia.org/wiki/Closed_platform" target="_blank">walled gardens&lt;/a>&amp;rsquo;, uh, walls.&lt;/p>
&lt;p>I spent most of web 2.0 (2005-2015?) as a &lt;a href="https://www.yanisvaroufakis.eu/2023/11/03/the-big-idea-has-the-digital-economy-killed-capitalism-the-guardian/" target="_blank">digital serf&lt;/a> - tilling the big platforms&amp;rsquo; fields (Facebook, Twitter, etc) with data that was precious to me. My memories! Pics of college and grad school! Old friends! Parties! Trips! Extracting that data out of the platforms has always been onerous, but I&amp;rsquo;ve been doing it for a few years now. De-Googling, as you can imagine, has been taking forever. But I have de-gmailed! And that got me thinking. If I move from ProtonMail to FastMail or wherever, I&amp;rsquo;ll have to keep telling my contacts that my e-mail address changed. What if I can keep that fixed - and just swap out the back-end? HMMMM.&lt;/p>
&lt;p>So that&amp;rsquo;s the idea with the self-hosted UI for the cloud LLMs. I&amp;rsquo;m retaining a streaming, constant copy of my data locally, on my NAS. (Otherwise I&amp;rsquo;m just tilling OpenAI and Anthropic&amp;rsquo;s fields, and have to manually export my data whenever I remember.) This way, yes, they still get my data (&amp;ldquo;Khaaaaaaaan!&amp;rdquo; as Kirk would say), but at least &lt;em>I have it too&lt;/em>. And I can delete it from their servers whenever I want (presumably&amp;hellip;). And once I&amp;rsquo;m ready to buy a GPU and stand up a local, semi-powered, &lt;em>truly private&lt;/em> AI, I can cut the chord completely.&lt;/p>
&lt;h1 class="relative group">Fun OpenWebUI features
&lt;div id="fun-openwebui-features" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#fun-openwebui-features" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/local_ai_setup/screenshot_hu13fca5e91c73fa4d2e9c11fafa775077_46916_330x0_resize_box_3.png 330w,
/posts/local_ai_setup/screenshot_hu13fca5e91c73fa4d2e9c11fafa775077_46916_660x0_resize_box_3.png 660w,
/posts/local_ai_setup/screenshot_hu13fca5e91c73fa4d2e9c11fafa775077_46916_1024x0_resize_box_3.png 1024w,
/posts/local_ai_setup/screenshot_hu13fca5e91c73fa4d2e9c11fafa775077_46916_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/local_ai_setup/screenshot_hu13fca5e91c73fa4d2e9c11fafa775077_46916_660x0_resize_box_3.png"
alt="a screenshot of openwebui on mobile, with an AI persona called techbro"
/>
&lt;/figure>
OpenWebUI is super powerful; &lt;a href="https://docs.openwebui.com/" target="_blank">docs here&lt;/a>. My use cases for LLMs are fairly basic:&lt;/p>
&lt;ul>
&lt;li>Chatting&lt;/li>
&lt;li>Some coding&lt;/li>
&lt;li>Sometimes some more involved projects (OCR + translation + summarization)&lt;/li>
&lt;/ul>
&lt;p>I don&amp;rsquo;t really enjoy AI slop art, and haven&amp;rsquo;t yet gotten into text-to-speech (though I have been thinking &lt;a href="https://www.harihareswara.net/posts/2022/speech-to-text-with-whisper-how-i-use-it-why/" target="_blank">about Whisper&lt;/a>). I have zero interest in nightmarish video gen.&lt;/p>
&lt;p>For &lt;strong>chatting&lt;/strong>, I had a glorious prompt on the Anthropic UI for a &amp;ldquo;techbro neckbeard&amp;rdquo;. He was the &amp;ldquo;persona&amp;rdquo; I spoke with the most. Basically, I told him to be a typical Redditor, all lowercase, very snide, judgmental, etc. The &amp;ldquo;WELL ACKshually&amp;rdquo; guy. I ported that persona over to OpenWebUI, added a profile pic (you can add profile pics for your custom models!!), inserted the same Anthropic Claude-4-sonnet brain, and, voila, now I have my asshole AI assistant back!! Man, this guy makes me laugh and laugh. Also, super interestingly, while both the Claude UI and OpenWebUI neckbeard personas always assumed I was a dude (sigh&amp;hellip;), the OpenWebUI techbro was also way more overtly sexist and rude. Wow!! Are there more guardrails on the Claude UI chat vs. the Claude API? I wonder&amp;hellip; Anyway, I had to adjust his prompt to be a &lt;em>feminist&lt;/em> techbro, jeez.&lt;/p>
&lt;p>I have a few more AI personas I enjoy - man, I&amp;rsquo;m really living the &lt;a href="https://en.wikipedia.org/wiki/Hyperion_%28Simmons_novel%29" target="_blank">Dan Simmons&amp;rsquo;s Hyperion&lt;/a> dream here. I have a solarpunk lady and a fitness guru lady. I used to have a Thomas Bayes econometrics/stats friend - he would speak in 19th century English minister talk, very amusing. I have had dark sci-fi thoughts about making personas for my loved ones that have died 😱. But no! Must not literally recreate &lt;a href="https://en.wikipedia.org/wiki/Be_Right_Back" target="_blank">that one Black Mirror episode&lt;/a>. 😬&lt;/p></description></item><item><title>Reflecting on a year of attempted sustainability</title><link>https://www.angelaambroz.com/posts/sustainability/</link><pubDate>Thu, 10 Jul 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/sustainability/</guid><description>&lt;p>In July 2024, I read Kim Stanley Robinson&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/The_Ministry_for_the_Future" target="_blank">The Ministry for the Future&lt;/a> and it had &lt;a href="https://www.goodreads.com/review/show/4110839187" target="_blank">a profound effect on me&lt;/a>. It appealed to lots of long-time personal and professional passions: rationality, sustainability, technocratic solutions to social failings, saving the world. It triggered one of my hyperfocus periods - where I become all-consumed by a topic and obsess over it and adjust my life around it. These are always very educational periods.&lt;/p>
&lt;p>It is now exactly one year later from that Goodreads review - and I spent a &lt;em>lot&lt;/em> of time trying to apply the book&amp;rsquo;s green fire to my daily life. Let&amp;rsquo;s do a retro and see how I did, and what I&amp;rsquo;ll change or keep going forward.&lt;/p>
&lt;h1 class="relative group">What I was trying to do
&lt;div id="what-i-was-trying-to-do" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#what-i-was-trying-to-do" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;h2 class="relative group">Climate nihilism
&lt;div id="climate-nihilism" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#climate-nihilism" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>For context: as Alan Tudyk&amp;rsquo;s alien would say, I am a &lt;a href="https://www.youtube.com/shorts/kD7Q8pTVTm4" target="_blank">basic bitch&lt;/a> educated liberal. Pre-the book, I most certainly believed that human-caused climate change was real, but I was &lt;em>also&lt;/em> suffering from spoon-fed NYT climate anxiety and climate nihilism (&amp;ldquo;it&amp;rsquo;s too late&amp;rdquo;, or &amp;ldquo;individual action is pointless&amp;rdquo;). I was aware of &amp;ldquo;greenwashing&amp;rdquo; and knew that I should be mindful of it, I liked the bag tax at the grocery store, but - good Lord - do not give me another tote, please!&lt;/p>
&lt;p>I didn&amp;rsquo;t look too deeply into climate science or the state of climate change work in 2024 because it just made me depressed and anxious. Also I felt overwhelmed. I didn&amp;rsquo;t know where to start. I didn&amp;rsquo;t want to think about it too much, though I definitely thought that &lt;em>someone&lt;/em> should think about it (please?). Indeed, it took me months to get the courage to read KSR&amp;rsquo;s book!&lt;/p>
&lt;p>All that definitely changed with the book. After reading it, I felt inspired and empowered. I &lt;em>loved&lt;/em> KSR&amp;rsquo;s repeated notion that it will take a multitude of actions - large and small - to bend this curve of climate disaster. There was no one, true way, no &amp;ldquo;perfect&amp;rdquo; silver bullet. Just a lot of work! I loved how characters repeatedly talked about &amp;ldquo;putting [their] shoulder to the wheel&amp;rdquo;. I loved how the book portrayed this multitude of actions, and was ambivalent on which were actually effective: knee-jerk geoengineering following a murderous Indian heat wave, violent eco-terrorism, multilateral cooperation akin to Bretton Woods, regenerative farms and rewilding. It all felt very believable (something KSR &lt;a href="https://www.kimstanleyrobinson.info/content/musing-about-optopias" target="_blank">has spoken about&lt;/a> - writing &amp;ldquo;optopias&amp;rdquo; (best case realistic scenarios) versus dystopias or utopias). Indeed, a lot of it &lt;a href="https://en.wikipedia.org/wiki/30_by_30" target="_blank">is real&lt;/a>!&lt;/p>
&lt;p>So! Given all that! What did I want to do?&lt;/p>
&lt;h2 class="relative group">Guiding principles
&lt;div id="guiding-principles" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#guiding-principles" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Basically, I was guided by two principles:&lt;/p>
&lt;ol>
&lt;li>&amp;ldquo;Be part of the solution, not the problem.&amp;rdquo;&lt;/li>
&lt;li>&amp;ldquo;Be on the right side of history - aka, what will my descendants think of me?&amp;rdquo;&lt;/li>
&lt;/ol>
&lt;p>Vague - but that was the idea. Instead of climate nihilism, I decided to give it my best shot - specifically on reducing &lt;strong>carbon emissions&lt;/strong> and &lt;strong>plastic waste&lt;/strong>, as much as I could, from where I sit.&lt;/p>
&lt;h2 class="relative group">How to apply the principles
&lt;div id="how-to-apply-the-principles" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-to-apply-the-principles" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I then spent a LOT of time musing about the most impactful ways to reduce carbon emissions and plastic waste. (Well, the latter is pretty straightforward - more on that below.) Should I protest? Chain myself to an oil rig? Write my legislators? (ha ha sob) Never fly again? Buy an EV? Donate to a climate change group? Go &lt;a href="https://en.wikipedia.org/wiki/Zero_waste" target="_blank">zero waste&lt;/a>? Bike a lot? Be vegan?&lt;/p>
&lt;p>The world was my oyster! KSR gave me tons of ideas! And, finally diving headfirst into the world of climate change activism, I saw that - well, a LOT is going on. But I wanted to be impactful. I have a full-time tech job and full-time domestic/childcare work, so I knew I didn&amp;rsquo;t want to exhaust myself on peanuts. I &lt;em>also&lt;/em> recognized that I was &amp;ldquo;doing&amp;rdquo; a lot of stuff already - buying plastic when I could avoid it, etc - and so maybe I could start changing the underlying systems of my life. What were the passive ways in which I was &amp;ldquo;part of the problem&amp;rdquo; and could I switch those out?&lt;/p>
&lt;h2 class="relative group">🏭 Taking stock
&lt;div id="-taking-stock" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#-taking-stock" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I also realized, pretty quickly, that quantifying all of this would be a bit of an art. There are a ton of online calculators for &lt;strong>individual carbon emissions&lt;/strong> - I mostly relied on &lt;a href="https://www.earthhero.org/" target="_blank">Earth Hero&lt;/a> and &lt;a href="https://coolclimate.berkeley.edu/calculator" target="_blank">UC Berkeley&amp;rsquo;s CoolClimate Calculator&lt;/a> - but I tried several, and my estimates had a pretty wide range. Nonetheless, they gave me a sense of scale - and the main takeaways were: (1) the American lifestyle is not sustainable (per capita emissions are bananas), and (2) flying and food waste are big problems. Also, I waffled a bit on whether I should measure my &lt;em>individual&lt;/em> vs. &lt;em>household&lt;/em> emissions?&lt;/p>
&lt;p>Quantifying &lt;strong>plastic use&lt;/strong> was, again, more straightforward. The city where I live collects paper recycling, compost, and everything else in 3 distinct bins. I just wanted to minimize that last bin. So I could weigh it. I&amp;hellip; could. I did not.&lt;/p>
&lt;h1 class="relative group">Okay, what I actually did (&amp;ndash; and whether I think it was a hit 🎉 or miss 😖)
&lt;div id="okay-what-i-actually-did----and-whether-i-think-it-was-a-hit--or-miss-" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#okay-what-i-actually-did----and-whether-i-think-it-was-a-hit--or-miss-" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;h2 class="relative group">📚 Learning:
&lt;div id="-learning" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#-learning" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>🎉 In gathering info on WHAT to do, I ended up using the &lt;a href="https://www.earthhero.org/" target="_blank">Earth Hero&lt;/a> app as my anchor. &lt;em>Tons&lt;/em> of great ideas in here, highly recommend.&lt;/li>
&lt;li>🎉 I discovered and subscribed to a ton of excellent climate reporting: &lt;a href="https://grist.org/" target="_blank">Grist&lt;/a> was an amazing discovery, as was &lt;a href="https://www.resilience.org/" target="_blank">Resilience&lt;/a> and &lt;a href="https://yaleclimateconnections.org/" target="_blank">Yale Climate Connections&lt;/a>. The &lt;a href="https://www.mothersofinvention.online/" target="_blank">Mothers of Invention podcast&lt;/a> was also great and got me regularly fired up.&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">🏠 ✈ House + movement:
&lt;div id="--house--movement" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#--house--movement" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>😖 Signed up for &lt;a href="https://www.energy.gov/eere/solar/community-solar-basics" target="_blank">community solar&lt;/a>. It&amp;rsquo;s one year later and we are &lt;em>still&lt;/em> waiting for our solar array to get set up.&lt;/li>
&lt;li>🎉 Cargo ebike! This replaced a TON of car rides (e.g. daily commute with kids), and we rode it all year round. Big success!&lt;/li>
&lt;li>🎉 Replaced all shampoo, conditioner, hand soaps with bar soaps. Easy. Done!&lt;/li>
&lt;li>🎉 Replaced toothpaste with &lt;a href="https://kagi.com/search?q=toothpaste&amp;#43;tablets" target="_blank">toothpaste tablets&lt;/a>.&lt;/li>
&lt;li>🎉 Replaced household cleaning supplies (laundry, dishes) with zero waste alternatives. Quite onerous to do - you have to hunt for your local specialty zero waste shop, mamma mia.&lt;/li>
&lt;li>🎉 Got composting back online! Fetid stink yey.&lt;/li>
&lt;li>😖 Reused those damn tote bags. Sometimes?&lt;/li>
&lt;li>😖 I seriously investigated alternatives to flying. I remember meeting a climate activist in Berlin in 2017 who told me he attended some workshop in NYC&amp;hellip; by boat. At the time, his behavior felt extreme, overly zealous. Now, it seems perfectly rational. The &amp;ldquo;&lt;a href="https://en.wikipedia.org/wiki/Flight_shame" target="_blank">flight shame&lt;/a>&amp;rdquo; movement has picked up a bit of steam - mostly in densely-connected Europe. My two big flying commitments are (1) business trips every ~4 months, and (2) family trips twice a year. I didn&amp;rsquo;t think I could drag the family on a transatlantic sea voyage, but maybe I could find a transcontinental train route to get to the work meetings? Nope. &lt;a href="https://www.amtrak.com/long-distance-train-experience" target="_blank">Amtrak does have a way to get across America by train&lt;/a> - but the options are very limited, mostly geared towards tourists (not work travellers), and THREE TIMES THE PRICE of flying (if you want a private room&amp;hellip; and I did, for 3 days&amp;rsquo; worth of travel!).&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">🥦 👚 Consumption:
&lt;div id="--consumption" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#--consumption" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>🎉 Damn, I think I had beef only like 2-3 times this year? Good for me. But!&lt;/li>
&lt;li>😖 BUT WELL ACKshually, &lt;a href="https://ourworldindata.org/grapher/food-emissions-supply-chain" target="_blank">cheese and chocolate are worse than prosciutto&lt;/a> (!), and I cannot bear to give those up. I half-heartedly tried to only eat eco chocolate, but my beloved Lindt - even with its &lt;a href="https://www.snopes.com/news/2024/12/31/lindt-chocolate-heavy-metals/" target="_blank">cadmium and lead&lt;/a> - still reigns supreme on my taste buds!!&lt;/li>
&lt;li>🎉 Reduced online shopping to a bare minimum. I mostly bought digital items (books, etc) and second hand stuff.&lt;/li>
&lt;li>🎉 Didn&amp;rsquo;t buy any new clothes, only second hand! Discovered the vibrant world of online thrifting, glory be.&lt;/li>
&lt;li>🎉 Successfully ruined everyone&amp;rsquo;s Christmas by insisting that we do no gifts - everyone got a &lt;a href="https://gifts.worldwildlife.org/gift-center/?sc=AWY1700OQ18553A01640RX" target="_blank">World Wildlife Fund animal &amp;ldquo;adoption&amp;rdquo;&lt;/a> instead. YOU&amp;rsquo;RE WELCOME.&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">💰 Wealth:
&lt;div id="-wealth" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#-wealth" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>🎉 Moved money out of climate chaos-causing mainstream banks and into institutions that are more sustainable, per &lt;a href="https://bank.green/" target="_blank">Bank.Green&lt;/a>. See also this amusing &lt;a href="https://yaleclimateconnections.org/2024/02/inside-my-quest-for-a-climate-friendly-bank/" target="_blank">Yale Climate Connections piece&lt;/a>.&lt;/li>
&lt;li>😖 Retirement accounts are still invested in fossil fuel industries.&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">✊ Activism:
&lt;div id="-activism" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#-activism" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>😖 Started a green club at work. My idea was - I can use my leverage as an employee to steer the company towards, e.g., reporting its emissions, investing in &lt;a href="https://scholar.harvard.edu/files/kremer/files/amc_pp_20_20_01_13.pdf" target="_blank">advance market commitments&lt;/a>(a la &lt;a href="https://frontierclimate.com/" target="_blank">Frontier&lt;/a>), offering regenerative ag CSAs as a wellness perk, etc. Unfortunately, I just did not realistically have the bandwidth to lead this actively. So, for now, it&amp;rsquo;s just a collection of eco colleague-stragglers and we send each other articles every month or so. It&amp;rsquo;s very sad.&lt;/li>
&lt;li>🎉 Became a monthly donor to my local climate activist groups. Most of these are pretty mainstream political advocacy groups, &lt;em>not&lt;/em> the spicier, civil disobedient ones. I was deemed &lt;a href="https://www.sunrisemovement.org/" target="_blank">too old&lt;/a> for my favorite one lol, and apparently Europe is where all the cool &lt;a href="https://parentsforfuture.org/" target="_blank">old people activism is&lt;/a> (even one just &lt;a href="https://knittingforclimate.com/" target="_blank">for me!&lt;/a>).&lt;/li>
&lt;li>😖 Attended a civil disobedience climate group, but didn&amp;rsquo;t stick with it. Again, a lot of this is time. I think Gandhi, MLK Jr. and &lt;a href="https://www.youtube.com/watch?v=lsO_SlA7E8k" target="_blank">Mario Savio were right&lt;/a> - sometimes you have to put your body onto the gears of the machine to make it stop - but I just couldn&amp;rsquo;t find a way to plug in here that actually worked for me.&lt;/li>
&lt;li>😖 Similarly, volunteering with my local &amp;ldquo;mainstream&amp;rdquo; climate activist groups also didn&amp;rsquo;t work: I tried plugging in as a tech volunteer, but that fizzled out. I did some pro bono work for a friend&amp;rsquo;s biodiversity startup. I attended lots of Zoom intro calls, as well as a couple calls with local legislators (yay). But nothing seemed to click, nothing felt impactful, it felt like I was trying to climb a slippery slope and all I could ever concretely do was sign a petition. There must be a way in that is sustainable for the busy working parent?!&lt;/li>
&lt;/ul>
&lt;h1 class="relative group">Conclusions from a year of attempted sustainability
&lt;div id="conclusions-from-a-year-of-attempted-sustainability" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#conclusions-from-a-year-of-attempted-sustainability" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>After a year of this work, how would I rate it? What will I take forward?&lt;/p>
&lt;h2 class="relative group">Climate nirvana is painful
&lt;div id="climate-nirvana-is-painful" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#climate-nirvana-is-painful" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I think most educated people in the world accept that human-caused climate change is (a) happening and (b) bad. When you don&amp;rsquo;t pay attention to it, though, you don&amp;rsquo;t really know &lt;em>how&lt;/em> bad. My vague, unsettled, NYT-driven climate anxiety was unhelpful. I would swing between fairly big extremes: either fearing apocalyptic, civilizational collapse, or trying to reassure myself that &amp;ldquo;science would fix it somehow, surely it&amp;rsquo;ll be okay&amp;rdquo;.&lt;/p>
&lt;p>So, well, &lt;em>THANK YOU&lt;/em> so much to KSR - one of my top 2 living sci-fi authors! - for presenting a believable prediction for this century. It was scary, sometimes horrifyingly so. But it was also informative - and galvanizing. Humanity will be OK, we are resilient. Which is another way of saying that humanity can bear a lot of suffering. So let&amp;rsquo;s try to minimize that suffering!&lt;/p>
&lt;p>After reading the book, I did spend a couple weeks in a haze - similar to what Richard Feynman described after working on the Manhattan Project. I looked at everyone as mindless sheeple. I was living encased in a fuzzy bubble of cosmic perspective - who cares about this work deadline when our society is hurtling towards disaster? &lt;em>Did you just buy a pack of toothpaste tubes from Amazon - are you trying to kill us all?!&lt;/em> Not a good way to be. But also: the natural part of internalizing something quite stark!&lt;/p>
&lt;p>Several climate activism resources - &lt;a href="https://peterkalmus.net/" target="_blank">Peter Kalmus&lt;/a> comes to mind - speak about this being a normal part of the process. First, you have to grieve. I really agree with that now.&lt;/p>
&lt;p>We are going to hit a wall of ecological reality sometime this century. We can either hit the wall going full-speed, causing massive suffering, or we can navigate this change on our own terms, skillfully. We have the knowledge and the resources! We just need&amp;hellip; okay, we need global collective action. Which is not looking too hot right now, to be fair.&lt;/p>
&lt;p>And individually, trying to live with this reality in mind - just the practical aspects of living within Earth&amp;rsquo;s limit, as an individual/household - was sometimes massively difficult. And always for quite stupid, irrational reasons. You find yourself pushing against enormous systemic forces. Seriously, have you tried finding toothpaste tablets with flouride? It is a challenge! And why don&amp;rsquo;t we have &lt;em>way more overnight trains, hello?!&lt;/em> Reducing emissions and plastic can become a full-time job. Just like living free of Big Tech is almost like opting out of modern society, living a carbon neutral and zero plastic life was basically impossible.&lt;/p>
&lt;h2 class="relative group">That said - climate nirvana was oddly joyous?
&lt;div id="that-said---climate-nirvana-was-oddly-joyous" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#that-said---climate-nirvana-was-oddly-joyous" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Basically, even though my actions were a drop in the bucket, when things clicked - they really, really clicked!&lt;/p>
&lt;p>Cory Doctorow (my &lt;em>other&lt;/em> top 2 living sci-fi author, surprise!!) has this quote about fighting a fight that you don&amp;rsquo;t &amp;ldquo;win&amp;rdquo;, you just fight. &lt;a href="https://www.joannamacy.net/main" target="_blank">Joanna Macy&lt;/a> also had some stuff to say about this on the &lt;a href="https://resources.soundstrue.com/we-are-the-great-turning-podcast/" target="_blank">We are the Great Turning&lt;/a> podcast - a sort of Buddhist non-attachment to a particular outcome, even as you work for&amp;hellip; a particular outcome. And I think that&amp;rsquo;s healthy: balancing the grief with joy and optimism - and pragmatism!&lt;/p>
&lt;p>I noticed how, as I dove &lt;em>very&lt;/em> deep on the climate change activism reading, I found some &lt;a href="https://en.wikipedia.org/wiki/Doomer" target="_blank">doomerist&lt;/a> strains - dark and scary nihilism, death culty stuff about how we&amp;rsquo;d all be living in a Mad Max hellscape by 2100. These would be written by authoritative voices - scientists, etc. Brrrr, I shudder. And just not for me. To paraphrase Kant, being optimistic is a way to stay sane and keep plugging away. (Plus, history is littered with catastrophes and, as far as I can tell, these people cannot see into the future!)&lt;/p>
&lt;p>Anyway, on the practical side: the parts of my solarpunk lifestyle that worked &lt;em>really&lt;/em> worked. The joy of e-biking was just - chef&amp;rsquo;s kiss. (And you can park anywhere!) The ease of shopping less: having less junk, less cardboard boxes, less plastic bags. Less clutter! The fun and sensible-ness of thrifting. &lt;em>Not giving or receiving a bunch of stuff at Christmas!&lt;/em> LESS STUFF. Mamma mia, we can BREATHE again. And regenerative ag fruit and vegetables! Very good.&lt;/p>
&lt;h2 class="relative group">Future plans
&lt;div id="future-plans" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#future-plans" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The one thing KSR&amp;rsquo;s book also brought home was &lt;strong>the importance of imagination&lt;/strong>. I discovered &lt;a href="https://en.wikipedia.org/wiki/Solarpunk" target="_blank">solarpunk&lt;/a> through him, and just having access to a positive vision of the future was so, so valuable. It gives you something to work towards. My go-to utopia has always been Star Trek - specifically, The Next Generation - but that&amp;rsquo;s very far future (and does include, okay, a sentient AI war and major societal collapse between them and us). Solarpunk is much more accessible! Why, I feel like most of the Netherlands is living the solarpunk life right now (all those bike lanes!!!!).&lt;/p>
&lt;p>So, given that, I&amp;rsquo;m going to:&lt;/p>
&lt;ol>
&lt;li>Keep cultivating a positive, solarpunk framing through fiction, art, essays, whatever. It&amp;rsquo;s important to imagine &lt;em>how things could go right&lt;/em>.&lt;/li>
&lt;li>Keep doing the 🎉 good stuff.&lt;/li>
&lt;li>Pick &lt;strong>one&lt;/strong> &amp;ldquo;collective action&amp;rdquo;-y activity and try to really understand how I can plug in and be impactful. There must be something between &amp;ldquo;sign online petition&amp;rdquo; and &amp;ldquo;spend hours during your workday in a local legislator&amp;rsquo;s office&amp;rdquo;, right? Right????&lt;/li>
&lt;/ol></description></item><item><title>Fixing subtitles for obscure movies</title><link>https://www.angelaambroz.com/posts/subtitles/</link><pubDate>Mon, 07 Jul 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/subtitles/</guid><description>&lt;p>One of my favorite movie genres is &lt;a href="https://en.wikipedia.org/wiki/Commedia_all%27italiana" target="_blank">commedia all&amp;rsquo;italiana&lt;/a> - aka, &amp;ldquo;Italian-style comedy&amp;rdquo; - aka, Italian tragicomedies with sharp socio-political edges, mostly made in the 1970s. Two of my favorite examples from this genre are Ettore Scola&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/The_Pizza_Triangle" target="_blank">Dramma della gelosia&lt;/a> and, uh, Ettore Scola&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/We_All_Loved_Each_Other_So_Much" target="_blank">C&amp;rsquo;eravamo tanto amati&lt;/a>. (Scola was good at this!)&lt;/p>
&lt;p>Anyway, the tragedy of these great commedie all&amp;rsquo;italiana is that they&amp;rsquo;re getting a bit lost in the mists of time. They&amp;rsquo;re still pretty well-known in Italy, but they&amp;rsquo;re definitely being forgotten in other countries. This is a damn shame! Especially when commedia all&amp;rsquo;italiana directors like &lt;a href="https://en.wikipedia.org/wiki/Lina_Wertm%C3%BCller" target="_blank">Lina Wertmüller&lt;/a> made history by being the first female director to be nominated for a Best Director Oscar.&lt;/p>
&lt;p>So I&amp;rsquo;m always trying to push these movies onto people - and that usually means struggling to find English-language subtitles. In 2012, I think I painstakingly &lt;em>wrote my own subtitles&lt;/em> for a few of these films. Those &lt;code>.srt&lt;/code> files are buried somewhere in my hard drives. Today, I am way less time-rich, and - after ripping my ancient DVDs into Plex - I was gratified to see that Plex lets you &lt;a href="https://support.plex.tv/articles/subtitle-search/" target="_blank">search and select for subtitles from the player UI itself&lt;/a>. The problem was that most of these subtitles were just a little bit offset - they&amp;rsquo;d be a few seconds too early or late, depending on whether the subs came from a slightly different DVD version than mine. Plex has a &lt;a href="https://support.plex.tv/articles/subtitle-offsets/" target="_blank">subtitle offset button&lt;/a> that does, well, &lt;a href="https://www.reddit.com/r/PleX/comments/1e6a01n/adjust_subtitle_offset_does_nothing/" target="_blank">nothing&lt;/a>. So&amp;hellip; what do?&lt;/p>
&lt;h3 class="relative group">Solution: Thank you, &lt;code>ffsubsync&lt;/code>!
&lt;div id="solution-thank-you-ffsubsync" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#solution-thank-you-ffsubsync" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Open source to the rescue! Thankfully the &lt;a href="https://github.com/smacke/ffsubsync" target="_blank">ffsubsync&lt;/a> does just what I need. After &lt;a href="https://www.opensubtitles.com/" target="_blank">downloading&lt;/a> some subtitles for my obscure Italian movies, I tried it out locally:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ffs C_ERAVAMO_TANTO_AMATI.m4v -i ceravamo.srt -o ceravamo_fixed.srt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This worked!!!
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/subtitles/screenshot1_hua0e52cfb6b0503f6c64781fb61bee4d7_428358_330x0_resize_box_3.png 330w,
/posts/subtitles/screenshot1_hua0e52cfb6b0503f6c64781fb61bee4d7_428358_660x0_resize_box_3.png 660w,
/posts/subtitles/screenshot1_hua0e52cfb6b0503f6c64781fb61bee4d7_428358_1024x0_resize_box_3.png 1024w,
/posts/subtitles/screenshot1_hua0e52cfb6b0503f6c64781fb61bee4d7_428358_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/subtitles/screenshot1_hua0e52cfb6b0503f6c64781fb61bee4d7_428358_660x0_resize_box_3.png"
alt="a scene from ceravamo tanto amati"
/>
&lt;/figure>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/subtitles/screenshot2_hudc36a2814a71ec4dc22e0c0e3c9ac8e3_705568_330x0_resize_box_3.png 330w,
/posts/subtitles/screenshot2_hudc36a2814a71ec4dc22e0c0e3c9ac8e3_705568_660x0_resize_box_3.png 660w,
/posts/subtitles/screenshot2_hudc36a2814a71ec4dc22e0c0e3c9ac8e3_705568_1024x0_resize_box_3.png 1024w,
/posts/subtitles/screenshot2_hudc36a2814a71ec4dc22e0c0e3c9ac8e3_705568_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/subtitles/screenshot2_hudc36a2814a71ec4dc22e0c0e3c9ac8e3_705568_660x0_resize_box_3.png"
alt="another scene from ceravamo tanto amati"
/>
&lt;/figure>
Glory be!!! Ah-Romaaaaaaaa&amp;hellip; moh si parla!&lt;/p>
&lt;h3 class="relative group">Doing it on the NAS?
&lt;div id="doing-it-on-the-nas" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#doing-it-on-the-nas" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Okay, so it works! Now I needed to get my environment set up on my NAS. I&amp;rsquo;m sure there&amp;rsquo;s automated packages that do all these steps, but I wanted something very very minimal (both to start and to maintain). For now, that just meant:&lt;/p>
&lt;ol>
&lt;li>Downloading the Python package from Docker Hub. This package creates a tiny Debian box with the latest Python.&lt;/li>
&lt;li>&lt;code>apt-get update &amp;amp;&amp;amp; apt-get install ffmpeg&lt;/code> - Ol&amp;rsquo; reliable &lt;a href="https://ffmpeg.org/" target="_blank">ffmpeg&lt;/a> is the main dependency.&lt;/li>
&lt;li>Set up a Python virtualenv and &lt;code>pip install ffsubsync&lt;/code> into it.&lt;/li>
&lt;li>Download the subs I need from OpenSubtitles.com.&lt;/li>
&lt;li>And voila!&lt;/li>
&lt;/ol>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/subtitles/screenshot3_hu01a69f6e6ca4ed9face3e54a650fc13d_1378474_330x0_resize_box_3.png 330w,
/posts/subtitles/screenshot3_hu01a69f6e6ca4ed9face3e54a650fc13d_1378474_660x0_resize_box_3.png 660w,
/posts/subtitles/screenshot3_hu01a69f6e6ca4ed9face3e54a650fc13d_1378474_1024x0_resize_box_3.png 1024w,
/posts/subtitles/screenshot3_hu01a69f6e6ca4ed9face3e54a650fc13d_1378474_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/subtitles/screenshot3_hu01a69f6e6ca4ed9face3e54a650fc13d_1378474_660x0_resize_box_3.png"
alt="a scene from dramma della gelosia"
/>
&lt;/figure>
&lt;/p>
&lt;p>Culture REVIVED!! Glory be. 🎉 Let us now gaze lovingly at a young &lt;a href="https://en.wikipedia.org/wiki/Giancarlo_Giannini" target="_blank">Giancarlo Giannini&lt;/a>&amp;rsquo;s long eyelashes, and chuckle at his amusing comments about Scandi polyamory ho ho ho. Seriously, readers, I highly recommend these movies.&lt;/p></description></item><item><title>On being an Obsidian power user</title><link>https://www.angelaambroz.com/posts/obsidian/</link><pubDate>Thu, 03 Jul 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/obsidian/</guid><description>&lt;p>My boss recently called me an &amp;ldquo;Obsidian power user&amp;rdquo; and - how flattering! So let us take a tour of this, ahem, POWER.&lt;/p>
&lt;h1 class="relative group">What be Obsidian?
&lt;div id="what-be-obsidian" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#what-be-obsidian" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>&lt;a href="https://obsidian.md/" target="_blank">Obsidian&lt;/a> is a closed source note-taking app. It has cultural roots and overlap with the &lt;a href="https://en.wikipedia.org/wiki/Zettelkasten" target="_blank">Zettelkasten&lt;/a> knowledge management system/lifestyle/philosophy, and has lots of overlap with &lt;a href="https://evernote.com/" target="_blank">Evernote&lt;/a> - which is what I used for many years, before it became progressively &lt;a href="https://en.wikipedia.org/wiki/Enshittification" target="_blank">enshittified&lt;/a>.&lt;/p>
&lt;p>What I like about Obsidian, and what keeps it very sticky for me, is:&lt;/p>
&lt;ul>
&lt;li>Notes are kept in Markdown (&lt;code>.md&lt;/code>) files. Soooo&amp;hellip;&lt;/li>
&lt;li>You can use Markdown syntax: especially &lt;code>code snippets&lt;/code>,&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>code blocks
&lt;/code>&lt;/pre>&lt;p>and LaTeX-ish math. You can do all your usual Markdown/HTML things, like linking across notes, across the web, embedding images and&amp;hellip; uh, that&amp;rsquo;s it, I think?&lt;/p>
&lt;p>But honestly: nice formatting of code, writing, and math = good enough for me!&lt;/p>
&lt;p>Obsidian and the Zettelkasten people also tout its pretty graph representation of knowledge, e.g. my knowledge as a ball:&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/obsidian/screenshot_hu4f6f07c4aab3b1facaac88456072b519_73929_330x0_resize_box_3.png 330w,
/posts/obsidian/screenshot_hu4f6f07c4aab3b1facaac88456072b519_73929_660x0_resize_box_3.png 660w,
/posts/obsidian/screenshot_hu4f6f07c4aab3b1facaac88456072b519_73929_1024x0_resize_box_3.png 1024w,
/posts/obsidian/screenshot_hu4f6f07c4aab3b1facaac88456072b519_73929_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/obsidian/screenshot_hu4f6f07c4aab3b1facaac88456072b519_73929_660x0_resize_box_3.png"
alt="A screenshot of an Obsidian graph view"
/>
&lt;/figure>
&lt;/p>
&lt;p>Tbh I never found much use of the ball o&amp;rsquo; thoughts view.&lt;/p>
&lt;h1 class="relative group">How I use Obsidian
&lt;div id="how-i-use-obsidian" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-i-use-obsidian" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>Every morning, when I open the Obsidian app on my personal or work laptop, my &lt;strong>daily note&lt;/strong> springs up - auto-populated with its daily template (core plugin: &lt;a href="https://help.obsidian.md/plugins/daily-notes" target="_blank">daily notes&lt;/a>). The title of this note is always a date, string-formatted to &lt;code>YYYY-MM-DD (day of week).md&lt;/code>. I also enabled a nifty auto-conversion of natural language dates, so that if I type &amp;ldquo;@Yesterday&amp;rdquo;, it automatically converts it to &amp;ldquo;2025-07-02 (Wednesday)&amp;rdquo; which &lt;em>also&lt;/em> becomes a clickable link to that day&amp;rsquo;s note 🤯 (community plugin: &lt;a href="https://github.com/argenos/nldates-obsidian" target="_blank">nldates&lt;/a>).&lt;/p>
&lt;p>Anyway, this daily note template includes tons of emoji (community plugin: &lt;a href="https://github.com/phibr0/obsidian-emoji-shortcodes" target="_blank">emoji shortcodes&lt;/a>), because I am a super-basic visual person and emoji are the new hieroglyphics and they give me joy. The template includes three main sections:&lt;/p>
&lt;ol>
&lt;li>✅ TODOs
&lt;ol>
&lt;li>🔁 Daily rituals&lt;/li>
&lt;li>🎯 Today&amp;rsquo;s specific TODOs&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>📓 NOTES&lt;/li>
&lt;li>🧠 Some meta-analysis about what I&amp;rsquo;m working on&lt;/li>
&lt;/ol>
&lt;p>All the ✅TODOs are tasks (community plugin: &lt;a href="https://github.com/obsidian-tasks-group/obsidian-tasks" target="_blank">tasks&lt;/a>) which I format to allow for partial completion and not-doings (theme: &lt;a href="https://github.com/colineckert/obsidian-things" target="_blank">things&lt;/a>). I give each task a time estimate (e.g. &amp;ldquo;30m&amp;rdquo;) and flag it as &lt;code>#work&lt;/code> or &lt;code>#personal&lt;/code>, as well as a due date (if applicable). As you can see, this is a bit of a Frankenstein mish-mash of the plugins&amp;rsquo; capabilities and what I like.&lt;/p>
&lt;p>For 🔁 daily rituals, these are the things I do to &amp;ldquo;clear my desk&amp;rdquo; every day - checking work notifications, &lt;a href="https://asana.com/resources/inbox-zero" target="_blank">zero inbox&lt;/a>, &lt;a href="https://apps.ankiweb.net/" target="_blank">Anki&lt;/a>, and a reminder to frickin&amp;rsquo; MOVE (aka some kind of exercise, eating vegetables, etc).&lt;/p>
&lt;p>For 🎯 today&amp;rsquo;s TODOs, I &lt;em>used&lt;/em> to just append an ever-increasing number of things here, but lately I&amp;rsquo;ve switched:&lt;/p>
&lt;ul>
&lt;li>I keep a &lt;code>BACKLOG.md&lt;/code> note, where I dump all the stuff I will eventually need/want to do.&lt;/li>
&lt;li>I pull 2-3 TODOs into my daily note for today.
Keeping this short and focused makes it way more likely I actually achieve &lt;em>something&lt;/em> by the end of the day.&lt;/li>
&lt;/ul>
&lt;p>For 📓 NOTES, this is where I just brain dump all my thoughts about my tasks - as I work through them. It&amp;rsquo;s where I scribble pseudo-code snippets, draft docs (including blog posts!), meeting notes, &lt;a href="https://www.reddit.com/r/todayilearned/" target="_blank">TIL&lt;/a>s and notes to self, etc. This can be short or long.&lt;/p>
&lt;p>And now - the pièce de résistance! - I discovered recently that, since Obsidian is basically a webpage (HTML, Markdown, JavaScript, CSS) - you can&amp;hellip; CODE-IFY IT?!! aka I discovered that you can write short JavaScript-esque snippets to analyze your notes (community plugin: &lt;a href="https://github.com/blacksmithgu/obsidian-dataview" target="_blank">dataviewjs&lt;/a>). So I have a little code block in my daily template, co-written by Claude, that parses my notes and my BACKLOG.md to give an estimate of how much time I&amp;rsquo;m planning to work (this is a good sanity check!) and if there&amp;rsquo;s anything urgent bubbling up from the backlog. Here it is:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">function&lt;/span> &lt;span class="nx">getTodayFileName&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nb">Date&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">formatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">Intl&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">DateTimeFormat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;en&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">year&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;numeric&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">month&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;short&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">day&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;2-digit&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">weekday&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;long&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">parts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">formatter&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">formatToParts&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">date&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">values&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">parts&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">reduce&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">acc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">part&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">acc&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">part&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">type&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">part&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">acc&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span> &lt;span class="p">{});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="sb">`discord/&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">values&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">year&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">-&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">values&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">month&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">-&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">values&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">day&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb"> (&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">values&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">weekday&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">).md`&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Get today&amp;#39;s tasks
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">todayFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">getTodayFileName&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">let&lt;/span> &lt;span class="nx">todaysTasks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">dv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">page&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">todayFile&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">tasks&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Found tasks:&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">todaysTasks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Get waiting tasks from backlog
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">backlogFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;discord/BACKLOG.md&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">waitingTasks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">dv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">page&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">backlogFile&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">tasks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">includes&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;#waiting&amp;#39;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Found waiting tasks:&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">waitingTasks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Get tasks that are due soon or past due
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Create a date 7 days in the future
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">today&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nb">Date&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">sevenDaysLater&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nb">Date&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">sevenDaysLater&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">setDate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">today&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">getDate&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Filter for tasks with due dates in next 7 days
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Assuming due dates are in format 📅 YYYY-MM-DD
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">dueSoonTasks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">dv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">page&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">backlogFile&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">tasks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">dueDateMatch&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">match&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sr">/📅\s*(\d{4}-\d{2}-\d{2})/&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="nx">dueDateMatch&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">dueDate&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nb">Date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">dueDateMatch&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">dueDate&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="nx">sevenDaysLater&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">completed&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Found due soon tasks:&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">dueSoonTasks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Parse all tasks
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kd">function&lt;/span> &lt;span class="nx">parseTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">timeMatch&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">match&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sr">/(\d+)([mh])/&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">timeEst&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">timeMatch&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="nb">parseInt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">timeMatch&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">timeUnit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">timeMatch&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="nx">timeMatch&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">mins&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">timeUnit&lt;/span> &lt;span class="o">===&lt;/span> &lt;span class="s1">&amp;#39;h&amp;#39;&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="nx">timeEst&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">60&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="nx">timeEst&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">dueDateMatch&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">match&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sr">/📅\s*(\d{4}-\d{2}-\d{2})/&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">dueDate&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">dueDateMatch&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nb">Date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">dueDateMatch&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="kc">null&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">isWaiting&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">includes&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;#waiting&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">text&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sr">/⏲ \d+[mh]/&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sr">/📅\s*\d{4}-\d{2}-\d{2}/&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">trim&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">mins&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">mins&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">dueDate&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">dueDate&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">isWaiting&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">isWaiting&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">completed&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">completed&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">willNotDo&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">status&lt;/span> &lt;span class="o">===&lt;/span> &lt;span class="s1">&amp;#39;-&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">let&lt;/span> &lt;span class="nx">parsedTodaysTasks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[...&lt;/span>&lt;span class="nx">todaysTasks&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">parseTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">let&lt;/span> &lt;span class="nx">parsedWaitingTasks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[...&lt;/span>&lt;span class="nx">waitingTasks&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">parseTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">let&lt;/span> &lt;span class="nx">parsedDueSoonTasks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[...&lt;/span>&lt;span class="nx">dueSoonTasks&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">parseTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Calculate total time (excluding waiting tasks)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">activeTasksOnly&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">parsedTodaysTasks&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">isWaiting&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">completed&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">willNotDo&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">totalMins&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">activeTasksOnly&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">reduce&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">sum&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">sum&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">mins&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">header&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sb">`🧠 Today&amp;#39;s workload: &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nb">Math&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">floor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">totalMins&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">h &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">totalMins&lt;/span>&lt;span class="o">%&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">m`&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Show tasks due soon
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">header&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;📅 Due Soon&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">table&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;Task&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Due Date&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Time Est.&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parsedDueSoonTasks&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="nx">filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dueDate&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">completed&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">willNotDo&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="nx">sort&lt;/span>&lt;span class="p">((&lt;/span>&lt;span class="nx">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">a&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dueDate&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="nx">b&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dueDate&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">text&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dueDate&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">dueDate&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">toISOString&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;T&amp;#39;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">mins&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="sb">`&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nb">Math&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">floor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">mins&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">h &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">mins&lt;/span>&lt;span class="o">%&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">m`&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Show waiting tasks
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">dv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">header&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;⏳ Waiting On&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">dv&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">list&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parsedWaitingTasks&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="nx">filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">isWaiting&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="o">!&lt;/span>&lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">completed&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="nx">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">t&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">t&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Overall, I use &lt;a href="https://syncthing.net/" target="_blank">syncthing&lt;/a> to keep my notes synched between work and personal laptops, as well as my phone.&lt;/p>
&lt;h1 class="relative group">The once and future king
&lt;div id="the-once-and-future-king" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-once-and-future-king" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>I&amp;rsquo;ve been using Obsidian now for a few years. It&amp;rsquo;s very sticky. I like it a lot. The &lt;em>one thing&lt;/em> that I miss from my Macbook days is a good time tracker - e.g. I really miss &lt;a href="https://qotoqot.com/qbserve/" target="_blank">Qbserve&lt;/a>, which served me well for many years indeed. I&amp;rsquo;ve tried &lt;a href="https://activitywatch.net/" target="_blank">ActivityWatch&lt;/a>, a Linux FOSS alternative, but it didn&amp;rsquo;t Just Work ™ in the usual way and I eventually got fed up with it. I might give it another shot, but&amp;hellip; well, I do miss seeing my &lt;em>actual&lt;/em> time worked (rather than estimated time worked).&lt;/p>
&lt;p>Another nice-to-have might be integrated &lt;a href="https://en.wikipedia.org/wiki/Pomodoro_Technique" target="_blank">Pomodoro&lt;/a>? Though I&amp;rsquo;ve been pretty happy with using my physical hourglass (!).&lt;/p></description></item><item><title>Subscribing to GitHub releases</title><link>https://www.angelaambroz.com/posts/subscribing_to_github_releases/</link><pubDate>Tue, 03 Jun 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/subscribing_to_github_releases/</guid><description>&lt;p>Oh wow, this is handy. Noting this down! You can subscribe to a GitHub repo&amp;rsquo;s releases via RSS (thanks, &lt;a href="https://stackoverflow.com/questions/53988462/how-to-get-the-rss-feed-of-github-release-only-latest-release-exclude-pre-rel" target="_blank">trusty old StackOverflow&lt;/a>). I wanted to keep an eye on the &lt;a href="https://github.com/wallabag/wallabag/" target="_blank">Wallabag&lt;/a> repo, since I made a feature request about some relative URL referencing being broken. You can do that via RSS! &lt;a href="https://www.angelaambroz.com/posts/one_true_rss/">GLORIOUS RSS!&lt;/a> Just append &lt;code>.atom&lt;/code> to any releases page, e.g. &lt;a href="https://github.com/wallabag/wallabag/releases.atom" target="_blank">https://github.com/wallabag/wallabag/releases.atom&lt;/a>.&lt;/p></description></item><item><title>Reading things later with Wallabag and my Kobo</title><link>https://www.angelaambroz.com/posts/selfhosted_read_it_later/</link><pubDate>Mon, 26 May 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/selfhosted_read_it_later/</guid><description>
&lt;h1 class="relative group">Reading things later
&lt;div id="reading-things-later" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#reading-things-later" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>In 2014, I discovered &lt;a href="https://getpocket.com/" target="_blank">Pocket&lt;/a>. I was living in Tanzania and often took the ferry between Dar es Salaam and Zanzibar. This is about a 2.5-hour trip, and the internet dies out pretty quickly once you leave port. I paid for the &amp;ldquo;fancy&amp;rdquo; tickets and normally preferred sitting in the lounge, which had gigantic La-Z-Boy-type chairs and a big TV screen. I watched a &lt;em>lot&lt;/em> of Charlie Chaplin movies on those ferry trips. But! I also discovered the Pocket app, and it was a great way to pre-load a bunch of stuff to read while sailing.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/selfhosted_read_it_later/IMG_20140429_162428_hua2df31c812bd56a2d56537f438ca734c_182568_330x0_resize_q75_box.jpg 330w,
/posts/selfhosted_read_it_later/IMG_20140429_162428_hua2df31c812bd56a2d56537f438ca734c_182568_660x0_resize_q75_box.jpg 660w,
/posts/selfhosted_read_it_later/IMG_20140429_162428_hua2df31c812bd56a2d56537f438ca734c_182568_1024x0_resize_q75_box.jpg 1024w,
/posts/selfhosted_read_it_later/IMG_20140429_162428_hua2df31c812bd56a2d56537f438ca734c_182568_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/selfhosted_read_it_later/IMG_20140429_162428_hua2df31c812bd56a2d56537f438ca734c_182568_660x0_resize_q75_box.jpg"
alt="the port of dar es salaam"
/>
&lt;/figure>
&lt;/p>
&lt;p>After that initial burst in Tanzania, I rediscovered Pocket a couple years ago when I found that my browser (Firefox) and my e-reader (the Kobo) integrated with it. Reading it later&amp;hellip; &lt;em>in e-ink?!&lt;/em> Truly glorious.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/selfhosted_read_it_later/chart_hud594293052dcde8e15f4cdf3798e6d84_82784_330x0_resize_box_3.png 330w,
/posts/selfhosted_read_it_later/chart_hud594293052dcde8e15f4cdf3798e6d84_82784_660x0_resize_box_3.png 660w,
/posts/selfhosted_read_it_later/chart_hud594293052dcde8e15f4cdf3798e6d84_82784_1024x0_resize_box_3.png 1024w,
/posts/selfhosted_read_it_later/chart_hud594293052dcde8e15f4cdf3798e6d84_82784_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/selfhosted_read_it_later/chart_hud594293052dcde8e15f4cdf3798e6d84_82784_660x0_resize_box_3.png"
alt="chart"
/>
&lt;/figure>
&lt;/p>
&lt;h1 class="relative group">The end of Pocket
&lt;div id="the-end-of-pocket" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-end-of-pocket" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>Unfortunately, the good times are coming to an end - &lt;a href="https://support.mozilla.org/en-US/kb/future-of-pocket" target="_blank">Pocket is shutting down in July 2025&lt;/a>. I&amp;rsquo;ve already been moving as much as I can to self-hosted solutions (e.g. &lt;a href="https://www.angelaambroz.com/posts/one_true_rss/">all my news comes in via my self-hosted RSS reader&lt;/a>), and so I immediately went hunting for an alternative - ideally self-hostable and open source.&lt;/p>
&lt;p>The main ones I came across were:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://wallabag.org/" target="_blank">Wallabag&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://karakeep.app/" target="_blank">Karakeep&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://raindrop.io/" target="_blank">Raindrop&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/go-shiori/shiori" target="_blank">Shiori&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>I ended up going with Wallabag because it was: (a) open source, (b) self-hostable, (c) mature, and (d) I found several blog posts of people integrating it into their Kobo reading flow.&lt;/p>
&lt;h1 class="relative group">Setting up Wallabag on my Synology NAS
&lt;div id="setting-up-wallabag-on-my-synology-nas" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#setting-up-wallabag-on-my-synology-nas" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>As with my other self-hosted services, I relied on &lt;a href="https://github.com/wallabag/docker" target="_blank">the Docker Hub image&lt;/a> - I set the minimum environment variables up, got some help from Claude on how to debug the env vars lol, and then had the pain of exporting my Pocket saves and importing them into Wallabag.&lt;/p>
&lt;p>For now (an &lt;a href="https://github.com/wallabag/wallabag/pull/8186" target="_blank">open PR will change this&lt;/a>), the process is (1) Pocket exports a CSV, (2) but Wallabag wants to talk to Pocket via its API. Either way, I had 4k (!) Pocket saves, and Wallabag&amp;rsquo;s connection died a couple times trying to import everything. I&amp;rsquo;m assuming Pocket didn&amp;rsquo;t save the plaintext of the URLs, and so Wallabag had to ping 4k URLs to try to download the &lt;code>&amp;lt;body&amp;gt;&lt;/code> or whatever tags. How tedious! I haven&amp;rsquo;t checked yet, but I do hope Wallabag is now just &lt;em>saving&lt;/em> the plaintext of these articles.&lt;/p>
&lt;h2 class="relative group">&amp;hellip;and my Android and browser
&lt;div id="and-my-android-and-browser" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#and-my-android-and-browser" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The nice thing about Wallabag has been its maturity, as I said: it has an &lt;a href="https://github.com/wallabag/android-app" target="_blank">Android app&lt;/a> and &lt;a href="https://github.com/wallabag/wallabagger" target="_blank">browser extension&lt;/a> available. Note: the browser extension had a small fight with my browser re: HTTPS vs. HTTP.&lt;/p>
&lt;h1 class="relative group">The next big piece: the Kobo
&lt;div id="the-next-big-piece-the-kobo" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-next-big-piece-the-kobo" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>So the vanilla Kobo OS (?) is integrated with Pocket. (This was one of the big reasons I bought a Kobo! sob) I knew that switching to Wallabag, or any other option, really, would probably require jailbreaking it and loading &lt;a href="https://koreader.rocks/" target="_blank">KOReader&lt;/a>. This was actually super easy. There&amp;rsquo;s &lt;a href="https://www.mobileread.com/forums/showpost.php?p=3797096&amp;amp;postcount=2" target="_blank">an install.sh script&lt;/a>, but - honestly - it was literally just plugging in my Kobo, downloading the ZIP file and extracting it into the appropriate folder on the e-reader. &lt;a href="https://www.mobileread.com/forums/showthread.php?t=314220" target="_blank">Here&amp;rsquo;s the details.&lt;/a> It was totally painless - my Kobo immediately restarted, and now I had the KOReader option available on top of my vanilla Kobo menu.&lt;/p>
&lt;p>After setting up KOReader, it was just a matter of configuring the (built-in!) Wallabag integration to talk to my self-hosted instance. Doing this was actually a bit tricky, and took some brainstorming with Claude. Basically, my Kobo &lt;em>can&amp;rsquo;t&lt;/em> get on my &lt;a href="https://tailscale.com/" target="_blank">Tailscale&lt;/a> - which is how I connect to my self-hosted services when I&amp;rsquo;m not on the local nework. &lt;em>But&lt;/em> Wallabag&amp;rsquo;s PHP server insists that incoming HTTP requests, ahem, call it by its (domain) name. And so I just set the Docker&amp;rsquo;s env var, &lt;code>SYMFONY__ENV__DOMAIN_NAME&lt;/code> to &lt;em>both&lt;/em> the local network IP address &lt;em>and&lt;/em> the Tailnet IP address. This has broken my instance&amp;rsquo;s CSS and JS (ughhhhhh), but the basic functionality of &lt;code>save an article on my phone or laptop -&amp;gt; read it on my phone or Kobo&lt;/code> works - and that&amp;rsquo;s the most important thing!&lt;/p></description></item><item><title>Moving everything into RSS</title><link>https://www.angelaambroz.com/posts/one_true_rss/</link><pubDate>Sun, 06 Apr 2025 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/one_true_rss/</guid><description>
&lt;h1 class="relative group">NAS joy
&lt;div id="nas-joy" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#nas-joy" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>One of the few things that brings me true joy these days (!) is self-hosting. Bit by bit, I&amp;rsquo;ve been moving things into my little NAS - and each little app or service gives me just a little more feeling of dopamine and control during these unsettling times.&lt;/p>
&lt;p>Of course, I don&amp;rsquo;t always end up using the apps and services I self-host. For example, while I use the heck outta &lt;a href="https://www.plex.tv/" target="_blank">Plex&lt;/a>, I set up &lt;a href="https://tautulli.com/" target="_blank">Tautulli&lt;/a> and then&amp;hellip; forgot about it. Similarly for &lt;a href="https://pi-hole.net/" target="_blank">Pi-hole&lt;/a> (I know, I know) and a few others. I have a little garden of dead Docker containers.&lt;/p>
&lt;p>So it was with great pleasure that I both set up - &lt;em>and&lt;/em> became addicted to - my newest service: &lt;a href="https://freshrss.org/index.html" target="_blank">FreshRSS&lt;/a>.&lt;/p>
&lt;h1 class="relative group">RSSing my life
&lt;div id="rssing-my-life" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#rssing-my-life" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>A couple months ago, I read &lt;a href="https://pluralistic.net/2024/10/16/keep-it-really-simple-stupid/" target="_blank">Cory Doctorow&amp;rsquo;s blog, &amp;ldquo;You should be using an RSS reader&amp;rdquo;&lt;/a> and - as often happens with Cory (my lifestyle guru, I swear lol) - I was stupidly inspired. While some of Cory&amp;rsquo;s promises did not pan out - namely, I couldn&amp;rsquo;t find a way to RSS my USPS packages, and several big-name news orgs only provided a title and summary in their RSS feeds (NYT, FT) - I did end up finally finding a way to consolidate all those sporadic &amp;ldquo;cool people&amp;rdquo; I found on the internet and wanted to follow. All those blogs, newsletters, webcomics, and lesser-known news orgs. What&amp;rsquo;s even better is you can follow Bluesky and Mastodon accounts&amp;hellip; &lt;em>without&lt;/em> having a Bluesky or Mastodon account (YES, PLZ, FOR THE LOVE OF GAWD).&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/one_true_rss/freshrss_huf132337d6695b12b6dac4705db4fada4_312868_330x0_resize_box_3.png 330w,
/posts/one_true_rss/freshrss_huf132337d6695b12b6dac4705db4fada4_312868_660x0_resize_box_3.png 660w,
/posts/one_true_rss/freshrss_huf132337d6695b12b6dac4705db4fada4_312868_1024x0_resize_box_3.png 1024w,
/posts/one_true_rss/freshrss_huf132337d6695b12b6dac4705db4fada4_312868_1320x0_resize_box_3.png 2x"
src="https://www.angelaambroz.com/posts/one_true_rss/freshrss_huf132337d6695b12b6dac4705db4fada4_312868_660x0_resize_box_3.png"
alt="screenshot"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">A brief tutorial
&lt;div id="a-brief-tutorial" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#a-brief-tutorial" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Some notes for my future self, if my NAS ever dies. The process is pretty easy:&lt;/p>
&lt;ul>
&lt;li>Pull the FreshRSS Docker image from Docker Hub.&lt;/li>
&lt;li>Configuring a couple volumes to be mapped into the container: &lt;code>/data&lt;/code> and &lt;code>/extensions&lt;/code>. I hate this part. Years pass and I am still baffled by what Docker wants of me.&lt;/li>
&lt;li>Running the container. There&amp;rsquo;s an initial check which the container auto-runs to make sure it sees all the directories it needs. I remember some drama here of creating a user account and then promptly forgetting the password. I ended up having to go into the SQL database in the container to manually re-hash a password (LE SIGH).&lt;/li>
&lt;li>Then the fun part: adding RSS feeds!&lt;/li>
&lt;/ul>
&lt;p>What&amp;rsquo;s interesting is that RSS is kind of an old technology, and so most websites highlight their social media links. But, what&amp;rsquo;s even more interesting (amusing?), is that if you just add &lt;code>/rss/&lt;/code> or &lt;code>/feed/&lt;/code> to the top-level domain of some (WordPress?) websites, it auto-magically redirects to an XML-formatted RSS feed. I&amp;rsquo;m guessing that only a few &amp;ldquo;front end providers&amp;rdquo; (WordPress, Squarespace, etc) are the basis of a (vast?) majority of websites - so, as long as WordPress and Squarespace auto-handle RSS generation - then so do all their users&amp;rsquo; websites. At least, this worked a surprising number of times.&lt;/p>
&lt;p>Of course, all the crunchy intellectual web dorks of left-leaning politics loudly blared their RSS feeds - THANK YOU, to all of those. Oh yeah - and you can turn any Substack into an RSS (again, just append &lt;code>/feed/&lt;/code>, as in &lt;code>your_fave_author.substack.com/feed&lt;/code>).&lt;/p>
&lt;h2 class="relative group">Mobile
&lt;div id="mobile" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#mobile" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Ah yes, another very important use case is the ability to see all my feeds on my phone. There are a plethora of RSS apps. For now, I&amp;rsquo;m using &lt;a href="https://tailscale.com/" target="_blank">Tailscale&lt;/a> to create a secure connection to my NAS when I&amp;rsquo;m not on the local network. Then, in terms of mobile front end, I used one of FreshRSS&amp;rsquo;s &amp;ldquo;recommended&amp;rdquo; apps for Android: &lt;a href="https://capyreader.com/" target="_blank">Capy Reader&lt;/a>. I had to input the Tailscale IP - and I remember some futzing with login passwords and ports. Capy Reader syncs reads (which is the main thing I care about); I tried deleting a feed from the Capy Reader app, but this didn&amp;rsquo;t work. Similarly, I haven&amp;rsquo;t tried adding a feed either.&lt;/p>
&lt;h1 class="relative group">Two months in&amp;hellip;
&lt;div id="two-months-in" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#two-months-in" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>Two months in and my FreshRSS app is still one of my most-checked sites that I visit when I&amp;rsquo;m on my laptop.&lt;/p>
&lt;p>Stuff that works well:&lt;/p>
&lt;ul>
&lt;li>All the Substack newsletters are &lt;em>great&lt;/em> to read in the app. I&amp;rsquo;ve (re-)discovered Timothy Snyder, Timothy Garton Ash, and Adam Tooze. Yay, &lt;a href="https://www.ox.ac.uk/admissions/undergraduate/courses/course-listing/philosophy-politics-and-economics" target="_blank">PPE life&lt;/a>! I added a couple shortcuts from FreshRSS so that I can also immediately save an article to &lt;a href="https://getpocket.com/" target="_blank">Pocket&lt;/a> - which syncs automatically with my &lt;a href="https://www.kobo.com/" target="_blank">Kobo&lt;/a>. This is as close to a perfect flow as I can get!&lt;/li>
&lt;li>Another content type that works great has been webcomics - &lt;em>finally&lt;/em> an easy way to stay up to date with &lt;a href="https://xkcd.com/" target="_blank">xkcd&lt;/a> or &lt;a href="https://www.smbc-comics.com/" target="_blank">SMBC&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Stuff that doesn&amp;rsquo;t work well:&lt;/p>
&lt;ul>
&lt;li>The Bluesky feeds are high volume, low content, and often relying on embedded content (which FreshRSS strips). What usually ends up happening is that some Bluesky person posts something &amp;ldquo;outrage&amp;rdquo;-inducing, but I can&amp;rsquo;t even see the embedded context, and so I click through&amp;hellip; back to Bluesky. This back and forth is super tedious, and I&amp;rsquo;m debating just removing (all?) of the Bluesky/Mastodon stuff and just using those apps? This would be a real loss, though.&lt;/li>
&lt;li>Other high volume, low content stuff are any of the big name news orgs - e.g. Financial Times, you&amp;rsquo;re killing me here! While some news orgs - like &lt;a href="https://theintercept.com/" target="_blank">The Intercept&lt;/a>, &lt;a href="https://www.motherjones.com/" target="_blank">Mother Jones&lt;/a>, and &lt;a href="https://www.propublica.org/" target="_blank">ProPublica&lt;/a> - all thankfully post their entire article in the feed, many (NYT, FT, Economist, Wired) only post the summary. This is SUPER annoying right now. I &lt;em>think&lt;/em> there might be a way around this - e.g. if I need to log into each of those news orgs, maybe the full article will come through? But for now, I&amp;rsquo;ve just removed all of that noise.&lt;/li>
&lt;/ul>
&lt;h1 class="relative group">Overall
&lt;div id="overall" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#overall" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>Overall, this is great. I feel empowered and informed. I feel less like an algorithm is force-feeding me news, and more like I&amp;rsquo;m seeking out what I&amp;rsquo;m interested in and then keeping tabs on it. I&amp;rsquo;m excited to keep tinkering!&lt;/p></description></item><item><title>This blog is now brought to you by Hugo</title><link>https://www.angelaambroz.com/posts/moving_to_hugo/</link><pubDate>Wed, 10 Jul 2024 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/moving_to_hugo/</guid><description>&lt;p>Welp! It was time! Time for a big website refresh. Let&amp;rsquo;s talk through it.&lt;/p>
&lt;h1 class="relative group">2017 - 2024: Tech debt &amp;#x1f631;
&lt;div id="2017---2024-tech-debt-scream" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#2017---2024-tech-debt-scream" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>As a reminder, the previous version of this website was:&lt;/p>
&lt;ul>
&lt;li>originally written in HTML + CSS + a touch of Javascript, with just a few html pages (&lt;code>about.html&lt;/code>, &lt;code>scifi.html&lt;/code>, etc.)&lt;/li>
&lt;li>a &lt;a href="https://www.angelaambroz.com/posts/hello_pelican/">static blog generated by Pelican&lt;/a>
&lt;ul>
&lt;li>using a special Pelican theme on an outdated fork&lt;/li>
&lt;li>modified to match the CSS of my original, manually-written HTML + CSS&amp;hellip;&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>So I would use Pelican to generate the entire website, but I basically had everything spread out over four (4!!) directories/repos, and it was an awful pain to maintain. This was how things had been going since 2017. And it was just very very tech debty.&lt;/p>
&lt;h1 class="relative group">2022: Thinking about Hugo &amp;#x1f914;
&lt;div id="2022-thinking-about-hugo-thinking" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#2022-thinking-about-hugo-thinking" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>I had heard good things about &lt;a href="https://gohugo.io/" target="_blank">Hugo&lt;/a>, and thought it might be fun to try rewriting the blog in Hugo. This was back in 2022. I tinkered a bit, but then life got busy again and I dropped it.&lt;/p>
&lt;h1 class="relative group">2024: Moving to Hugo &amp;#x26f5;
&lt;div id="2024-moving-to-hugo-sailboat" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#2024-moving-to-hugo-sailboat" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>I picked it up again, &lt;a href="https://themes.gohugo.io/" target="_blank">found a theme&lt;/a> I liked (&lt;a href="https://blowfish.page/" target="_blank">Blowfish&lt;/a>), and decided to commit! This was a couple weekends&amp;rsquo; worth of work.&lt;/p>
&lt;h2 class="relative group">1. Quickstarting Blowfish with a bare Hugo site &amp;#x1f421;
&lt;div id="1-quickstarting-blowfish-with-a-bare-hugo-site-blowfish" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#1-quickstarting-blowfish-with-a-bare-hugo-site-blowfish" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>As a first step, I followed the &lt;a href="https://blowfish.page/docs/welcome/" target="_blank">Blowfish tutorial&lt;/a> to get a basic site up. Nothing special here.&lt;/p>
&lt;h2 class="relative group">2. Converting my Pelican blog to Hugo &amp;#x1f426;
&lt;div id="2-converting-my-pelican-blog-to-hugo-bird" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#2-converting-my-pelican-blog-to-hugo-bird" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I had about ~100 blog posts that needed to get Hugo-fied. I wrote a short Python script to rewrite their Markdown just a touch, mostly the frontmatter and relative references.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_file&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">filepath&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">read_dir&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">INPUT_DIRECTORY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">write_dir&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">THIS_DIR&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">verbose&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">verbose&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Now doing &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">filepath&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">read_dir&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">filename&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;r&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lines&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">readlines&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">frontmatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">body&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">in_frontmatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">subdir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">line&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">lines&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">in_frontmatter&lt;/span> &lt;span class="ow">and&lt;/span> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="k">match&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;^\w+:\s.*&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;:&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">key&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">lower&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;&amp;#34;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#39;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;:&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;-&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">key&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">VALID_PELICAN_KEYS&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">key&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;date&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">format_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">elif&lt;/span> &lt;span class="n">key&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;tags&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tag&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">tag&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;,&amp;#34;&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">elif&lt;/span> &lt;span class="n">key&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;category&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">category&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">category&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;,&amp;#34;&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">elif&lt;/span> &lt;span class="n">key&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;slug&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fpath&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">write_dir&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exists&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fpath&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">mkdir&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fpath&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">subdir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">elif&lt;/span> &lt;span class="n">key&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;summary&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">&amp;#34;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">frontmatter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">in_frontmatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="s2">&amp;#34;```{&amp;#34;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">line&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;```{&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;```&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">line&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{static}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">line&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{static}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="s2">&amp;#34;img&amp;#34;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">img_filename&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">re&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">findall&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">r&lt;/span>&lt;span class="s2">&amp;#34;\((.*)\)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="s2">&amp;#34;https&amp;#34;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">img_filename&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">verbose&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">img_filename&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># kinda hacky&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">img_filename&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">img_filename&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/&amp;#34;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fpath&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">write_dir&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">subdir&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">img_filename&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">listdir&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fpath&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Already here&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">rename&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">IMGS_DIRECTORY&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">img_filename&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">fpath&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">img_filename&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">line&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;imgs/&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">body&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">line&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In short, tons of string parsing - including some dreaded regexing. My workflow was mostly:&lt;/p>
&lt;ul>
&lt;li>Ask ChatGPT for boilerplate&lt;/li>
&lt;li>Try out regex in &lt;a href="https://regexr.com/" target="_blank">regexr&lt;/a>&lt;/li>
&lt;li>Tons of print statements to debug {chefs kiss}&lt;/li>
&lt;li>Sit at cafe and think about the state of the world.&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">3. Just do the whole website in Hugo actually &amp;#x1f421;
&lt;div id="3-just-do-the-whole-website-in-hugo-actually-blowfish" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#3-just-do-the-whole-website-in-hugo-actually-blowfish" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Namely, the static, non-blog pages, like &lt;a href="https://www.angelaambroz.com/scifi/">scifi&lt;/a>. This just took some understanding of how Hugo configs work.&lt;/p>
&lt;h2 class="relative group">4. Deploying &amp;#x1f680;
&lt;div id="4-deploying-rocket" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#4-deploying-rocket" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I deploy this site manually, just SCPing the files over to the server where it&amp;rsquo;s being hosted.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">scp -r public/* &lt;span class="nv">$WWW_USERNAME&lt;/span>@&lt;span class="nv">$WWW_IP_ADDRESS&lt;/span>:~/public_html/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Tadaaaaa! &amp;#x1f389;&lt;/p>
&lt;h1 class="relative group">80/20 it &amp;#x1f605;
&lt;div id="8020-it-sweat_smile" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#8020-it-sweat_smile" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>You may have noticed that some of the writing doesn&amp;rsquo;t show up, and the colors are a bit weird, and I think I still have draft posts sometimes showing up. Sigh.&lt;/p>
&lt;p>Anyway, I kept telling myself: 80/20, 80/20, 80/20. So I&amp;rsquo;m keeping a running list of things I&amp;rsquo;d like to fix or polish, but the main website is up and running - and that&amp;rsquo;s what matters!&lt;/p></description></item><item><title>The Best American Science And Nature Writing 2020 (2020) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/the_best_american_science_and_nature_writing_2020/</link><pubDate>Sun, 16 Jun 2024 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/the_best_american_science_and_nature_writing_2020/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/the_best_american_science_and_nature_writing_2020/book_jacket_hue35ec5e9eec5c17be9576660c64c54c6_68125_330x0_resize_q75_box.jpg 330w,
/posts/the_best_american_science_and_nature_writing_2020/book_jacket_hue35ec5e9eec5c17be9576660c64c54c6_68125_660x0_resize_q75_box.jpg 660w,
/posts/the_best_american_science_and_nature_writing_2020/book_jacket_hue35ec5e9eec5c17be9576660c64c54c6_68125_1024x0_resize_q75_box.jpg 1024w,
/posts/the_best_american_science_and_nature_writing_2020/book_jacket_hue35ec5e9eec5c17be9576660c64c54c6_68125_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/the_best_american_science_and_nature_writing_2020/book_jacket_hue35ec5e9eec5c17be9576660c64c54c6_68125_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Michio Kaku, and Jaime Green&lt;/li>
&lt;li>Number of pages: 384&lt;/li>
&lt;li>Year published: 2020&lt;/li>
&lt;li>Year read: 2024&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I always enjoy these essay collections. I was flustered that the editions cover the preceding year, so this one was actually 2019 articles. Aaarghhh. I wanted an overview of Covid science!! Oh well - onto the next one!&lt;br/>&lt;br/>This one had lots of gems. Stuff that really struck me:&lt;br/>- The horrors of California wildfires, as experienced on the ground.&lt;br/>- Two excellent paleontology articles (who knew I loved paleontology so much).&lt;br/>- An adorable buddy movie about astrophysicists trying to find Planet Nine.&lt;br/>- A heartbreaking one about a young girl&amp;rsquo;s mental health.&lt;br/>- A great one about immunotherapy.&lt;br/>&lt;br/>Less exciting was the stodgy New Yorker article about natural language processing, large language models (aka, LLMs, aka ChatGPT and &amp;ldquo;AI&amp;rdquo;). There wasn&amp;rsquo;t anything explicitly factually incorrect about it - it does a decent job of describing what LLMs are, etc - and I even agreed with some of the opinionated Luddite hand-wringing. But something altogether about it felt cringe.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/48930255" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Conspirituality- How New Age Conspiracy Theories Became a Public Health Threat (2023) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/conspirituality_how_new_age_conspiracy_theories_became_a_public_health_threat/</link><pubDate>Wed, 12 Jun 2024 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/conspirituality_how_new_age_conspiracy_theories_became_a_public_health_threat/</guid><description>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Derek Beres, and Matthew Remski, Julian Walker&lt;/li>
&lt;li>Number of pages: 384&lt;/li>
&lt;li>Year published: 2023&lt;/li>
&lt;li>Year read: 2024&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>A long-ish, engaging intellectual screed against the marriage of conspiracy theorizing and New Age woo. This was written with a lot of color and brio, so it&amp;rsquo;s a lot of fun and quite podcasty. &lt;br/>&lt;br/>This is a history of 20th and 21st century wellness movements - yoga, Reiki, all that New Agey stuff - and their underlying politics, as well as their often close relationship with conspiracy theories and cults. The first two parts are a lively sociological and historical study of this stuff, and I learned a lot and filled in lots of gaps that I had had. This was basically what I wanted to learn from &amp;lt;a href=https://www.goodreads.com/book/show/9255017-american-veda?from_search=true&amp;amp;from_srp=true&amp;amp;qid=HGPrL6drUm&amp;amp;rank=1&amp;quot;&amp;gt;American Veda&lt;/a>, a book I am too lazy to actually buy. So, it was a lot of fun! And cut very close to home, especially the Theosophists and Buddhism in the West stuff. [I look down at my Buddhist tattoo in some chagrin.]&lt;br/>&lt;br/>I didn&amp;rsquo;t care for Part 3, where the authors present a Wall of Shame of the worst &amp;ldquo;conspiritualists&amp;rdquo; in recent years. Oh yes - &amp;ldquo;conspirituality&amp;rdquo; is basically the tight coupling of alt-right Qanon craziness with New Age business, and how the Covid pandemic was like gas on that flame. The Part 3 Wall of Shame chapters profiled the most egregiously awful of these yoga-practicing, coffee-enema-ing, Covid/election denialist influencers. And honestly, I just don&amp;rsquo;t have the patience to listen to complete and utter garbage for chapter upon chapter.&lt;br/>&lt;br/>The final part zoomed in on more quotidian conspiritualists - the conspiritualist next door, if you will. This was, of course, much less outrage-inducing and much sadder. e.g. The breast cancer patient who refuses mainstream medicine and dies amidst her magical thinking and potions. Ugh. It&amp;rsquo;s just awful. So the book, ultimately, preaches compassion for these benighted and confused people. &lt;br/>&lt;br/>The book also discussed the tropes of conspiritual thinking: namely, I replace your reality with my own. A lot of this has to do with people&amp;rsquo;s ignorance re: the scientific method - and their disappointments in it (i.e. they expect science to be infallible and - once a scientific question is &amp;ldquo;answered&amp;rdquo;, the answer never changes). This is a real problem, indeed, and is the problem of MY CAREER, I would say: how do you get people comfortable with uncertainty? How do you convey the epistemology of the scientific methods(and statistics, do not even get me started)? Without them just completely jumping ship and swimming to crazy island?&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/62653934" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Workflow 2024</title><link>https://www.angelaambroz.com/posts/workflow_2024/</link><pubDate>Tue, 04 Jun 2024 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/workflow_2024/</guid><description>&lt;p>It&amp;rsquo;s been a while! Here&amp;rsquo;s how my workflow looks, in this post-LLM world.&lt;/p>
&lt;h2 class="relative group">Editor: Neovim
&lt;div id="editor-neovim" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#editor-neovim" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>After several happy years in Vim, I switched to Neovim. My &lt;a href="https://github.com/angelaambroz/.dotfiles" target="_blank">.dotfiles&lt;/a> will probably keep evolving, but, right now, I&amp;rsquo;m enjoying plugins like:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/folke/lazy.nvim" target="_blank">Lazy&lt;/a> - For plugin loading.&lt;/li>
&lt;li>&lt;a href="https://github.com/airblade/vim-gitgutter" target="_blank">Git gutter&lt;/a> - For &lt;code>:Git blame&lt;/code> all the damn time.&lt;/li>
&lt;li>&lt;a href="https://github.com/nvim-telescope/telescope.nvim" target="_blank">Telescope&lt;/a> - For &lt;em>very&lt;/em> quick and convenient file search.&lt;/li>
&lt;li>&lt;a href="https://github.com/mfussenegger/nvim-dap" target="_blank">DAP&lt;/a> - Debugging.&lt;/li>
&lt;li>&lt;a href="https://codeium.com/" target="_blank">Codeium&lt;/a> - LLM autocomplete. And this sometimes fights with &lt;a href="https://github.com/davidhalter/jedi-vim" target="_blank">Jedi&lt;/a>.&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Terminal: ZSH
&lt;div id="terminal-zsh" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#terminal-zsh" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Specifically, &lt;a href="https://ohmyz.sh/" target="_blank">oh-my-zsh&lt;/a>, with some autosuggestions and the &lt;a href="https://github.com/sindresorhus/pure" target="_blank">pure&lt;/a> for aesthetics.&lt;/p>
&lt;h2 class="relative group">ChatGPT &amp;gt; StackOverflow
&lt;div id="chatgpt--stackoverflow" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#chatgpt--stackoverflow" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Ever since the Great LLM Explosion of 2023, I haven&amp;rsquo;t really gone back to StackOverflow for my daily random questions. Instead, my usual workflow is:&lt;/p>
&lt;ul>
&lt;li>ChatGPT: Help me interpret this code, help me write code in a language I never use (e.g. React), what does X mean?&lt;/li>
&lt;li>&lt;a href="https://www.khanmigo.ai/" target="_blank">Khanmigo&lt;/a>: Help me (re-)learn the covariance matrix, or basic chemistry, or grad-level stats, and other things. I like Khanmigo (enough to pay for it) since they prompt engineered it to be Socratic and &amp;ldquo;truthy&amp;rdquo; (better than the usual bullshit-as-a-service ChatGPT).&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Desktop environment: Regolith
&lt;div id="desktop-environment-regolith" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#desktop-environment-regolith" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;ve been using &lt;a href="https://regolith-desktop.com/" target="_blank">Regolith&lt;/a> for a few years now - I think &lt;a href="https://www.youtube.com/c/theprimeagen" target="_blank">Primagean&lt;/a> had a video about his desktop environment, using some similar tool. What I love is its simplicity and ease of use. I usually have 4 &amp;ldquo;tab&amp;rdquo; desktops open (L-R): web browser, &lt;a href="https://obsidian.md/" target="_blank">Obsidian&lt;/a>, work Discord, a terminal, and something miscellaneous like Spotify. I have this for both my personal and work machines, and I love it so much that I&amp;rsquo;m worried I can&amp;rsquo;t live/work without it?!&lt;/p>
&lt;h2 class="relative group">OS: Pop!_OS
&lt;div id="os-pop_os" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#os-pop_os" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>It&amp;rsquo;s fine.&lt;/p>
&lt;h2 class="relative group">Notes/second brain: Obsidian
&lt;div id="notessecond-brain-obsidian" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#notessecond-brain-obsidian" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://obsidian.md/" target="_blank">Obsidian&lt;/a> is &lt;em>my jam&lt;/em>. I &lt;em>really&lt;/em> like it. Specifically, I love:&lt;/p>
&lt;ul>
&lt;li>I can take notes in Markdown, and then grep those notes super-quickly straight from the shell.&lt;/li>
&lt;li>I can write code blocks, LaTeX math blocks, headings, and tables are all supported.&lt;/li>
&lt;/ul>
&lt;p>OK, and galaxy brain here, but I set up automatic &amp;ldquo;smart&amp;rdquo; linking of dates (e.g. &lt;code>Today&lt;/code> becomes &lt;code>2024 Jun 6 (Tuesday)&lt;/code>) &lt;em>and&lt;/em> my daily notes template follows the same &lt;code>strftime&lt;/code> pattern. So it&amp;rsquo;s super easy to link to other notes using smart dates.&lt;/p></description></item><item><title>The Battle for Your Brain- Defending the Right to Think Freely in the Age of Neurotechnology (2023) - ⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/the_battle_for_your_brain_defending_the_right_to_think_freely_in_the_age_of_neurotechnology/</link><pubDate>Mon, 29 Apr 2024 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/the_battle_for_your_brain_defending_the_right_to_think_freely_in_the_age_of_neurotechnology/</guid><description>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Nita A. Farahany&lt;/li>
&lt;li>Number of pages: 288&lt;/li>
&lt;li>Year published: 2023&lt;/li>
&lt;li>Year read: 2024&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>A fun, wide-ranging, and provocative non-fiction book about the ethics and possibilities of neurotech (aka brain-meddling!!).&lt;br/>&lt;br/>So I spent most of this audiobook running and arguing with it in my head. I almost threw the headphones off in an angry huff during the &amp;ldquo;why ADHD meds are cognitive enhancers and totally fine ok&amp;rdquo; - I stuck with it, if only because I enjoyed the ethical debating. (Even though I do think the ADHD meds chapter was GOODNESS ME, really eliding some big, obvious downsides to ADHD meds (and steroids). Like, that shit can fuck you up.&lt;br/>&lt;br/>The author, Farahany, is a law prof and was on Obama&amp;rsquo;s bioethics committee. So I do defer to her authority. At the same time, I feel like I&amp;rsquo;m kinda not into the Singularity/transhumanist world anymore - and I did sense some techbro enthusiasm in Farahany&amp;rsquo;s writing, which made me eye-roll. But I can&amp;rsquo;t criticize her too much; she did a decent job of outlining the ethical debate.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/60784561" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Dawn of the New Everything- Encounters with Reality and Virtual Reality (2017) - ⭐⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/dawn_of_the_new_everything_encounters_with_reality_and_virtual_reality/</link><pubDate>Tue, 17 Oct 2023 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/dawn_of_the_new_everything_encounters_with_reality_and_virtual_reality/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/dawn_of_the_new_everything_encounters_with_reality_and_virtual_reality/book_jacket_hu30af33df73541382dd29f19e7d00323d_52077_330x0_resize_q75_box.jpg 330w,
/posts/dawn_of_the_new_everything_encounters_with_reality_and_virtual_reality/book_jacket_hu30af33df73541382dd29f19e7d00323d_52077_660x0_resize_q75_box.jpg 660w,
/posts/dawn_of_the_new_everything_encounters_with_reality_and_virtual_reality/book_jacket_hu30af33df73541382dd29f19e7d00323d_52077_1024x0_resize_q75_box.jpg 1024w,
/posts/dawn_of_the_new_everything_encounters_with_reality_and_virtual_reality/book_jacket_hu30af33df73541382dd29f19e7d00323d_52077_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/dawn_of_the_new_everything_encounters_with_reality_and_virtual_reality/book_jacket_hu30af33df73541382dd29f19e7d00323d_52077_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Jaron Lanier&lt;/li>
&lt;li>Number of pages: 368&lt;/li>
&lt;li>Year published: 2017&lt;/li>
&lt;li>Year read: 2023&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Jaron Lanier&amp;rsquo;s brain is a veritable wonderland. There is no one like him. I was absolutely DELIGHTED by much of this book - especially the memoir of his childhood and adolescence. He is really an inspiration. And so funny! And so smart! It&amp;rsquo;s like his brain is made of champagne fizz. Like the very best Star Trek: Next Generation episodes. &lt;br/>&lt;br/>Anyway, this book inspired me to try out virtual reality. &lt;br/>&lt;br/>Also, this book took me forever to read, HAHA. I basically started it, was delighted, got consumed by chess for a couple months, got distracted by my life for the next few months, picked it up and finished it. Womp!&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/23848323" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>In the Camps- China's High-Tech Penal Colony (2021) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/in_the_camps_chinas_hightech_penal_colony/</link><pubDate>Mon, 27 Feb 2023 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/in_the_camps_chinas_hightech_penal_colony/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/in_the_camps_chinas_hightech_penal_colony/book_jacket_hue0861850a73e73b6f78e807d6b8dbe8d_44486_330x0_resize_q75_box.jpg 330w,
/posts/in_the_camps_chinas_hightech_penal_colony/book_jacket_hue0861850a73e73b6f78e807d6b8dbe8d_44486_660x0_resize_q75_box.jpg 660w,
/posts/in_the_camps_chinas_hightech_penal_colony/book_jacket_hue0861850a73e73b6f78e807d6b8dbe8d_44486_1024x0_resize_q75_box.jpg 1024w,
/posts/in_the_camps_chinas_hightech_penal_colony/book_jacket_hue0861850a73e73b6f78e807d6b8dbe8d_44486_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/in_the_camps_chinas_hightech_penal_colony/book_jacket_hue0861850a73e73b6f78e807d6b8dbe8d_44486_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Darren Byler&lt;/li>
&lt;li>Number of pages: 150&lt;/li>
&lt;li>Year published: 2021&lt;/li>
&lt;li>Year read: 2023&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>A disturbing and distressing examination of the currently-happening &lt;a href="https://en.wikipedia.org/wiki/Uyghur_genocide">Uyghur genocide&lt;/a>, and how it&amp;rsquo;s accelerated by modern surveillance state technologies to create &amp;ldquo;smart&amp;rdquo; labor/reeducation camps. &lt;br/>&lt;br/>Just like the Nazis leveraged early 20th century industrialization to organize the Holocaust, so China is leveraging computer vision, smartphones, and machine learning to organize its own destruction of the Uyghur, Kazakh, and other ethnic minorities along its borders. A short book, but an informative and scary one! Darren Byler situates this genocide in the overall history of genocides and state surveillance; this book made me want to restart James Scott&amp;rsquo;s Seeing Like a State - since this book, and this genocide, is very much the eventual, worst extension of what Scott described: the creation of last names, street names, and order so that the state may &amp;ldquo;see&amp;rdquo;.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/58393878" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Digital for Good- Raising Kids to Thrive in an Online World (2021) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/digital_for_good_raising_kids_to_thrive_in_an_online_world/</link><pubDate>Tue, 13 Sep 2022 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/digital_for_good_raising_kids_to_thrive_in_an_online_world/</guid><description>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Richard E. Culatta&lt;/li>
&lt;li>Number of pages: 256&lt;/li>
&lt;li>Year published: 2021&lt;/li>
&lt;li>Year read: 2022&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Finding pro-screentime parenting advice is about as common as finding pro-formula tips. i.e. Completely uncommon because of an enormous cultural juggernaut that moralizes against it. I was starting to feel crazy trying to parse the WHY screens are demonized so totally for our kids - by pediatricians, by &amp;ldquo;conventional wisdom&amp;rdquo; etc. Why did I have so much guilt when plopping my kid in front of Peppa Pig? I think the official guidelines are zero screens before 2 years of age. I saw some parents asking if this meant no Zoom calls with grandparents. What!? What, exactly, do these people think screens are doing to their babies? &lt;br/>&lt;br/>I sometimes see some data and evidence trotted out: namely, kids who watch more TV are fatter and have more behavioral problems. Two questions, here:&lt;br/>1. Is this correlation or causation? Maybe hyperactive kids need TV to calm down?&lt;br/>2. If it&amp;rsquo;s causal (TV displaces physical activity), then isn&amp;rsquo;t any sedentary activity just as risky? Like, say, reading a book? Or drawing?&lt;br/>&lt;br/>Also, TV screens are quite different from phone screens and laptop screens?&lt;br/>&lt;br/>ANYWAY. So I was happy to find this book. I needed a sanity check. This book was very sanity restoring. He makes a few excellent points. Namely, we prepare our kids to live in the world - we teach them to look both ways, to brush their teeth, to be kind to most and careful around some. That&amp;rsquo;s all, ahem, IRL. This book makes the EXCELLENT point, that I - a tech person!!! - honestly never even thought about, which is that cyberspace exists and a lot of stuff happens there and so maybe we should&amp;hellip; parent for it? i.e. Just like you look both ways before crossing the street, you double check that sketchy e-mail attachment before downloading. Just like you don&amp;rsquo;t bully a kid in class, you also don&amp;rsquo;t troll a kid online. And so on.&lt;br/>&lt;br/>Culatta removed the high-pitched shriek of moral hysteria from my brain re: screens, and gave me the space and quiet to just THINK about it for a second. Having this space was liberating. And it scared me - how little ACTUAL THOUGHT I had given this issue of, ahem, what&amp;rsquo;s in the screens! Because abstinence is, indeed, a very stupid way to teach kids both about sex. AND SCREENS.&lt;br/>&lt;br/>One of his best ideas - which, again, duh, I feel stupid I never even thought about this - is that you can gradually introduce computers, the internet, and so on to your kids. Most apps have parental controls. But also: the choice isn&amp;rsquo;t between giving your tween a smartphone and a dumb phone. You can just dumb down an old smartphone - removing most apps, no data plan - and then gradually introduce things, piece by piece. &lt;br/>&lt;br/>The book covers lots of interesting things: &lt;br/>- online bullying (and how our &amp;ldquo;screen education&amp;rdquo; is literally only ever about that) &lt;br/>- the rise of echo chambers and fake media&lt;br/>- advertising, especially geared towards kid&lt;br/>- how you can (and should! and must!) turn off that damn autoplay feature on YouTube, Netflix, etc.&lt;br/>&lt;br/>And so on.&lt;br/>&lt;br/>Anyway, this got me pumped. I&amp;rsquo;ve been pumped about introducing a Raspberry Pi computer to my kids since forever. Now I am feeling even more emboldened. Perhaps you shall have indeed MORE PEPPA.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/57389178" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Split ergo keyboard</title><link>https://www.angelaambroz.com/posts/split_ergo_keyboard/</link><pubDate>Wed, 04 May 2022 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/split_ergo_keyboard/</guid><description>&lt;p>Oh God. Never have I had so many emotions over something as banal as a keyboard. But, after some research and a moment of madness, I decided to invest in a split ergonomic keyboard.&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/split_ergo_keyboard/2022-05-04_1_huc9983801026295d39d3f9446241ff5b5_3161834_330x0_resize_q75_box.jpg 330w,
/posts/split_ergo_keyboard/2022-05-04_1_huc9983801026295d39d3f9446241ff5b5_3161834_660x0_resize_q75_box.jpg 660w,
/posts/split_ergo_keyboard/2022-05-04_1_huc9983801026295d39d3f9446241ff5b5_3161834_1024x0_resize_q75_box.jpg 1024w,
/posts/split_ergo_keyboard/2022-05-04_1_huc9983801026295d39d3f9446241ff5b5_3161834_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/split_ergo_keyboard/2022-05-04_1_huc9983801026295d39d3f9446241ff5b5_3161834_660x0_resize_q75_box.jpg"
alt="moonlander"
/>
&lt;/figure>
&lt;/p>
&lt;p>This is the &lt;a href="https://www.zsa.io/moonlander/" target="_blank">ZSA Moonlander&lt;/a>, a stupid expensive mechanical keyboard that is super duper customizable, and also split and ergonomic (via being split and having &amp;ldquo;columnar&amp;rdquo; keys).&lt;/p>
&lt;p>Ever since my last pregnancy, I had been noticing some twinges - and occasional spikes - of pain around my wrists, thumb tendons, finger tendons. I started looking into ergonomics. It was especially painful when I picked my kids up after a long, sedentary day of, ahem, Tech Labor.&lt;/p>
&lt;p>So I started looking into keyboards and noodling around &lt;a href="mechanicalkeyboards.com/">mechanicalkeyboards.com&lt;/a>. And I was &lt;em>very&lt;/em> influenced by this &lt;a href="https://www.youtube.com/watch?v=wPGmZXAQRyw" target="_blank">Switch &amp;amp; Click video about trying a split keyboard for 30 days&lt;/a>. Switching to a split keyboard, especially a very customizable one where I could experiment - in the future - with other layouts (Dvorak, Coleman, stenography!), and take my time off in between jobs to re-learn to type&amp;hellip; well, it all seemed very rational. So I summoned my inner Picard and bravely declared MAKE IT SO and ordered it.&lt;/p>
&lt;p>And since then, dear reader, it has been, oh, &lt;em>such&lt;/em> an emotional rollercoaster. I&amp;rsquo;ve had it for 4 days and have wanted to throw it out the window maybe 100 times. Multiple times a day I need to remind myself to &amp;ldquo;keep the faith&amp;rdquo; and &amp;ldquo;no, a keyboard cannot literally make you stupid&amp;rdquo;. Because, oh dear reader, having my hands suddenly turn into two stupid meat paws has made me feel like my thoughts are now locked in my brain. (FWIW, I&amp;rsquo;m typing this on my laptop&amp;rsquo;s standard keyboard - so things are flowing! I wanted to give myself a break - and keep my old layout muscle memory going too.) And having my thoughts locked in my brain makes those thoughts wither and die. And that makes me stupid.&lt;/p>
&lt;p>But no! I vowed that I would persevere through this learning curve because all learning curves which lead to &lt;em>objectively&lt;/em> better tools/thinking/life (like Vim! Anki! Linux!) are worth surmounting. I must keep the faith. I must!!!&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/split_ergo_keyboard/2022-05-04_2_hu01008ae518e0fed9b40574bd308abdbb_32070_330x0_resize_q75_box.jpg 330w,
/posts/split_ergo_keyboard/2022-05-04_2_hu01008ae518e0fed9b40574bd308abdbb_32070_660x0_resize_q75_box.jpg 660w,
/posts/split_ergo_keyboard/2022-05-04_2_hu01008ae518e0fed9b40574bd308abdbb_32070_1024x0_resize_q75_box.jpg 1024w,
/posts/split_ergo_keyboard/2022-05-04_2_hu01008ae518e0fed9b40574bd308abdbb_32070_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/split_ergo_keyboard/2022-05-04_2_hu01008ae518e0fed9b40574bd308abdbb_32070_660x0_resize_q75_box.jpg"
alt="WPM over time"
/>
&lt;/figure>
&lt;/p>
&lt;p>I&amp;rsquo;m also trying to de-mystify the process and make myself less afraid of being locked in stupid meat paw brain forever by reminding myself that when I recently learned to crochet, I struggled oh so very mightily. After years and years of knitting, using my hands in this different, weird, crochet way was &lt;em>very&lt;/em> challenging. And after several false starts, I finally surmounted that learning curve and am now happily making amigurumi. (And crochet is 100% more rational than knitting - change my mind!)&lt;/p>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/split_ergo_keyboard/2022-05-04_3_hu80e050d796f349a6c05a4f78f3d1d3c7_284285_330x0_resize_q75_box.jpg 330w,
/posts/split_ergo_keyboard/2022-05-04_3_hu80e050d796f349a6c05a4f78f3d1d3c7_284285_660x0_resize_q75_box.jpg 660w,
/posts/split_ergo_keyboard/2022-05-04_3_hu80e050d796f349a6c05a4f78f3d1d3c7_284285_1024x0_resize_q75_box.jpg 1024w,
/posts/split_ergo_keyboard/2022-05-04_3_hu80e050d796f349a6c05a4f78f3d1d3c7_284285_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/split_ergo_keyboard/2022-05-04_3_hu80e050d796f349a6c05a4f78f3d1d3c7_284285_660x0_resize_q75_box.jpg"
alt="crochet"
/>
&lt;/figure>
&lt;/p>
&lt;p>&lt;span class="caption">Look at the creations now flowing from my hands! JUST LOOK.&lt;/span>&lt;/p>
&lt;h2 class="relative group">Goals
&lt;div id="goals" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#goals" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>My pre-split typing speed was ~100 WPM. My goal is to get to ~75 WPM on the split after 3 weeks. I &lt;em>think&lt;/em> I&amp;rsquo;m on track.&lt;/li>
&lt;li>I want to keep my non-split typing speed at minimum 90 WPM.&lt;/li>
&lt;li>I want my &lt;strong>coding&lt;/strong> typing speed to be &amp;ldquo;reasonable&amp;rdquo; - maybe 50 WPM? The more the better. I didn&amp;rsquo;t realize what a hit coding WPM would take&amp;hellip;&lt;/li>
&lt;li>I want to, obviously, &lt;em>not&lt;/em> have any new or additional pain in my hands and wrists (or shoulders).&lt;/li>
&lt;li>KEEP THE FAITH. TRUST THE PROCESS.&lt;/li>
&lt;/ul>
&lt;p>That&amp;rsquo;s it, man. I&amp;rsquo;m going to do the &amp;ldquo;deliberate&amp;rdquo; practice on &lt;a href="https://configure.zsa.io/" target="_blank">Oryx&lt;/a>, 30 min a day (10min 3x), and generally pray.&lt;/p></description></item><item><title>Job hunt 2022</title><link>https://www.angelaambroz.com/posts/job_hunt_2022/</link><pubDate>Wed, 27 Apr 2022 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/job_hunt_2022/</guid><description>&lt;p>I got a new job. I&amp;rsquo;ll be starting in a few weeks. I want to talk about the job search process since it&amp;rsquo;s been a while since I job hunted (I was at &lt;a href="https://www.optoro.com/" target="_blank">Optoro&lt;/a> for almost five years).&lt;/p>
&lt;h2 class="relative group">Some stats
&lt;div id="some-stats" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#some-stats" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Platforms I used to find opportunities: &lt;a href="https://www.glassdoor.com/" target="_blank">Glassdoor&lt;/a>, &lt;a href="https://www.linkedin.com/" target="_blank">LinkedIn&lt;/a>, &lt;a href="https://www.hired.com/" target="_blank">Hired&lt;/a>. the &lt;code>#jobs&lt;/code> channel on &lt;a href="https://pyladies.com/" target="_blank">PyLadies&lt;/a> Slack, a couple friends&lt;/li>
&lt;li>Applications I submitted &amp;ldquo;cold&amp;rdquo;: 48&lt;/li>
&lt;li>Applications I made via responding to recruiters: 10&lt;/li>
&lt;/ul>
&lt;p>Almost every position I applied to was titled &lt;strong>Senior Data Scientist&lt;/strong>, though there were a few &lt;strong>(Senior) Machine Learning Engineer&lt;/strong>s in there too.&lt;/p>
&lt;h2 class="relative group">The &amp;ldquo;average&amp;rdquo; interview process
&lt;div id="the-average-interview-process" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-average-interview-process" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The most common interview process was:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Recruiter screen (30 min)&lt;/strong>. The questions here were almost always: what&amp;rsquo;s your background? What are you looking for in a next role? What do you work on currently?&lt;/li>
&lt;li>&lt;strong>Tech screen (30 min - 1 hour)&lt;/strong>. The majority of these were live coding screens on &lt;a href="https://www.coderpad.io/" target="_blank">Coderpad&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Hiring manager call (30-45 min)&lt;/strong>. Meeting the potential boss, or boss&amp;rsquo;s boss.&lt;/li>
&lt;li>&lt;strong>Take-home assignment (many many hours)&lt;/strong>. Sometimes instead of the code screen. Sometimes in addition!&lt;/li>
&lt;li>&lt;strong>Final round (1+ days)&lt;/strong>. These often included an &lt;strong>additional tech screen/live coding&lt;/strong>, one or more &lt;strong>case study/technical deep dive interviews&lt;/strong>, and at least one &lt;strong>behavioral/culture interview&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Cracking the coding interview&amp;hellip; for data science
&lt;div id="cracking-the-coding-interview-for-data-science" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#cracking-the-coding-interview-for-data-science" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;blockquote>
&lt;p>&lt;strong>tldr&lt;/strong>: Listen to the question. Plan out your code using pseudocode/a bulleted TODO list that your interviewer can see. Execute on that TODO list. Practicing for performance anxiety was more worthwhile than grinding Leetcode.&lt;/p>
&lt;/blockquote>
&lt;p>The dreaded live coding interview!&lt;/p>
&lt;p>I &lt;em>dreaded&lt;/em> this step when I started applying, since I had had bad experiences previously: namely, having incredible performance anxiety, writing code that would run but still being rejected. Once I &amp;ldquo;cracked&amp;rdquo; this part of the interview (and disclaimer: ymmv), I then started passing these interviews&amp;hellip; even when my code had errors or I got stuck. I&amp;rsquo;ve been through about a dozen of these, so my experience may not representative.&lt;/p>
&lt;p>The live coding screens varied widely. I went through the following:&lt;/p>
&lt;ul>
&lt;li>&amp;ldquo;Do Python and SQL stuff, either &amp;lsquo;whiteboarding&amp;rsquo; on Coderpad or &amp;lsquo;open book&amp;rsquo; (i.e. you can Google syntax).&amp;rdquo; (most frequent)&lt;/li>
&lt;li>&amp;ldquo;Do data with Python but pretend you have no &lt;code>pandas&lt;/code>. Closed book.&amp;rdquo;&lt;/li>
&lt;li>&amp;ldquo;Use Google Colab, while screensharing, while I watch you use &lt;code>pandas&lt;/code>.&amp;rdquo;&lt;/li>
&lt;li>Big-O notation/algorithms and data structures.&lt;/li>
&lt;/ul>
&lt;p>When I started the job hunt, I was a bit frantic about how to prepare for these. I was at a loss. Should I spend an hour a day working my way up through LeetCode/HackerRank difficulty? Would I have to take an Algorithms &amp;amp; Data Structures online course? And so on.&lt;/p>
&lt;p>What I&amp;rsquo;ve concluded, having now gone through this round successfully several times, is:&lt;/p>
&lt;h4 class="relative group">No, Data Scientist applicants were not expected to know big-O notation
&lt;div id="no-data-scientist-applicants-were-not-expected-to-know-big-o-notation" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#no-data-scientist-applicants-were-not-expected-to-know-big-o-notation" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>Only one code screen (out of ~15) asked me about this, and I flatly said I didn&amp;rsquo;t have a CS undergrad background, had never taken Algorithms and Data Structures, but was willing to take a crack at it. I basically mused aloud about memory stuff (&lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/19/cs50_lecture_1/">thanks, CS50!&lt;/a>), the interviewer nudged me forward, and it was fine. I ended up getting an offer from this place!&lt;/p>
&lt;h4 class="relative group">Performance anxiety prep is as important - or maybe more important - than code prep
&lt;div id="performance-anxiety-prep-is-as-important---or-maybe-more-important---than-code-prep" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#performance-anxiety-prep-is-as-important---or-maybe-more-important---than-code-prep" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>In my case, the nerves were real. I went through a few code screens where I was &lt;em>extremely&lt;/em> nervous. I would jump in, frantically write spaghetti code, hit small syntax errors, get flustered, and then have a brain shut-down.&lt;/p>
&lt;p>They always advise you to &amp;ldquo;show your work&amp;rdquo; and &amp;ldquo;think out loud&amp;rdquo;; and my code and thoughts were a jumbled-up, gibbering mess. I would invariably get rejected after these screens, which hurt. I felt indignant. &amp;ldquo;I&amp;rsquo;ve been deploying Python to production for 5+ years! Of course I know how to zip two lists!&amp;rdquo; I&amp;rsquo;d think, annoyed with them and angry at myself the next day. But the anxiety crept into my practice as well. When I would sit down to do some Leetcode problems, I&amp;rsquo;d be hit with it: a faint voice in my head, screaming, &lt;em>You&amp;rsquo;re too stupid for this!&lt;/em>&lt;/p>
&lt;p>It took me a few more failures before I realized: gosh, maybe I&amp;rsquo;m not stupid, I&amp;rsquo;m just nervous? And maybe I could try to be less nervous? In college and grad school, I used to have &lt;em>awful&lt;/em> performance anxiety; I&amp;rsquo;ve had panic attacks before and during (!) exams. It sucked. Thankfully, after grad school, I learned a technique that really helped: &lt;strong>visualization&lt;/strong>.&lt;/p>
&lt;p>Basically, before the Big Day, I make a bulleted list of all the activities of that day: waking up, getting breakfast, shower, commute, etc. I then have two columns: &amp;ldquo;pre&amp;rdquo; and &amp;ldquo;post&amp;rdquo; anxiety, out of a scale of 1 (not anxious) to 10 (full-blown panic). I sit down with the list and force myself to really, deeply visualize each part of the day - each item of the list. I mark how anxious that specific image makes me: eating breakfast JUST HOURS BEFORE THE CODING INTERVIEW. Opening the Coderpad link. Saying &amp;ldquo;hi&amp;rdquo; to the interviewer. And so on. If my &amp;ldquo;pre&amp;rdquo; anxiety exceeds 5, I stop the visualization and do some &lt;a href="https://samatha.org/" target="_blank">calming breaths&lt;/a>. I then record my &amp;ldquo;post&amp;rdquo; anxiety - &amp;ldquo;post&amp;rdquo; meaning &amp;ldquo;after I tried to calm down a bit&amp;rdquo;. If I get back under 5, that&amp;rsquo;s fine. If not, that&amp;rsquo;s fine too.&lt;/p>
&lt;p>I do this repeatedly before the Big, Scary Event, maybe 2-3x on average&amp;hellip; and it&amp;rsquo;s worked wonders! It was the way I got over panic attacks before public speaking. It was the way I &amp;ldquo;cured&amp;rdquo; my fear of flying. And I realized - belatedly - that it would help me during this interview process! While I never properly panicked, I did realize that nerves were getting in the way of showing my skills. The visualization exercise helped &lt;em>tremendously&lt;/em>. To the point that, by about halfway through my job hunt, &lt;strong>I no longer felt anxious before code screens&amp;hellip; or any of the other interviews!&lt;/strong> 😱&lt;/p>
&lt;p>This was such a strange experience - interviewing while totally relaxed - that I was suspicious of it. Surely nerves also help? But in the end, I think it was a good thing, to be so relaxed. It helped me think much more clearly on the spot, especially when interviewers tossed tricky questions at me during the case study interviews. And I ended up really living the growth mindset: suddenly, I hungered for those hard questions and was disappointed when an interviewer didn&amp;rsquo;t challenge me! I felt like &lt;a href="https://www.youtube.com/watch?v=-UYgORr5Qhg" target="_blank">overqualified drummer&lt;/a>. And I think this intellectual restlessness - challenge me! - reflected well; more than one interviewer seemed pleasantly surprised that I said I enjoyed getting stuck (I did!). It also gave me a much better sense of what working with that person would be like (since I normally don&amp;rsquo;t have performance anxiety while in some random meeting with a work colleague I&amp;rsquo;ve known for a while).&lt;/p>
&lt;p>So, yeah. Anxiety + visualization = relaxation. And relaxation = growth mindset!&lt;/p>
&lt;h4 class="relative group">Another tip: slow and steady beats fast and &amp;ldquo;clever&amp;rdquo;
&lt;div id="another-tip-slow-and-steady-beats-fast-and-clever" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#another-tip-slow-and-steady-beats-fast-and-clever" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>I was once invited to attend a conference (at Harvard!) and then - surprise! - ended up being told &amp;ldquo;my panel was next&amp;rdquo;. Cue horror.&lt;/p>
&lt;p>I sat myself at the end of the quite-long panel table and waited while the other panelists introduced themselves. While they did - and my mind was spinning - I noticed that (a) I couldn&amp;rsquo;t follow their introductions easily, whether because they spoke softly or in a roundabout way or whatever, and (b) audience members had similar looks of confusion or glassy-eyed distraction. I resolved that, since I had no idea what to say on this panel, I could at least speak very &lt;em>loudly and clearly and simply&lt;/em>, just introducing the research org I worked for (and was, apparently, now representing) and the work we did. This went over swimmingly.&lt;/p>
&lt;p>It was a lesson I forgot. But I re-learned it during these coding screens. Just speaking &lt;em>slowly, clearly, and simply&lt;/em> goes a long, LONG way. Your interviewer is human. They can&amp;rsquo;t read your mind. They likely know very little about you - &lt;em>maybe&lt;/em> they&amp;rsquo;ve looked at your resume. Even then, likely only briefly. So just introducing yourself clearly, repeating your understanding of the question prompt back to them, and writing down - in Coderpad - the list of what you&amp;rsquo;re going to do&amp;hellip; oh man. That seemed to go a LONG way. I sometimes just wrote &lt;strong>SLOW DOWN&lt;/strong> on my whiteboard (out of sight).&lt;/p>
&lt;p>Before this realization, I would feel nervous as heck while the interviewer introduced themselves and talked in a leisurely way about the interview&amp;rsquo;s structure. I remember thinking, &amp;ldquo;Hurry, I need all the time I can get! Oh man!!&amp;rdquo; &lt;em>After&lt;/em> my &amp;ldquo;go slow, be obvious&amp;rdquo; realization, I would intentionally take it slow - I would &lt;em>not&lt;/em> rush through my intro, I would &lt;em>not&lt;/em> try to scan through the entire question prompt as soon as they pasted it in Coderpad. I would sometimes just take a moment to make a joke that felt funny. Basically, &lt;strong>I was not in a rush&lt;/strong>. And then, once I got around to actually answering the question, I would do something like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Q: [some easy-level Leetcode Python question]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">my_answer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">some_input&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">some_type&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">some_other_type&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> TODO:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> - create an empty array
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> - apply machine learning to the elements
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> - return some data type
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> - do other things
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Meaning: I very methodically (1) defined some function and type-hinted the heck out of it (look, interviewer, I know typing!), (2) made some docstring, (3) filled that docstring with my overkill thoughts. When I was learning how to code in Python, I remember I had to write out my plan in plain English or pseudocode. As I got more comfortable, I stopped needing to plan. WELL, NOW I AM BACK TO PLANNING. And it has made me much more effective. Again, my sample size is small, but once I started doing Angela the Sloth Candidate Who Loves Checklists, I passed all my code screens.&lt;/p>
&lt;h2 class="relative group">Cracking the knowledge interview (case study, tech deep dive)
&lt;div id="cracking-the-knowledge-interview-case-study-tech-deep-dive" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#cracking-the-knowledge-interview-case-study-tech-deep-dive" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;blockquote>
&lt;p>&lt;strong>tldr&lt;/strong>: Anki! OMG, Anki.&lt;/p>
&lt;/blockquote>
&lt;p>Actually, my math above is wrong. It should be: relaxation &lt;strong>+ Anki&lt;/strong> = growth mindset. I, like a lot of other people, read &lt;a href="https://www.goodreads.com/book/show/40745.Mindset?ac=1&amp;amp;from_search=true&amp;amp;qid=LzKgfpH1eF&amp;amp;rank=1" target="_blank">Carol Dweck&amp;rsquo;s book&lt;/a> and was like, yes. That sounds great. Of course. I should be growth mindset. But while the book made me &lt;em>aware&lt;/em> of &amp;ldquo;fixed mindset&amp;rdquo; thoughts, it didn&amp;rsquo;t necessarily give me a sense of how to actually, ahem, ~live the growth mindset lifestyle~.&lt;/p>
&lt;p>At the same time, a year or so ago, I discovered &lt;a href="http://augmentingcognition.com/ltm.html" target="_blank">Michael Nielsen&amp;rsquo;s amazing post, &lt;em>Augmenting Long-term Memory&lt;/em>&lt;/a>, where I learned about spaced repetition and the evidence-based way to build memory (aka knowledge). After reading that post, I had messed around with the Anki app for a few weeks, but it didn&amp;rsquo;t stick. I made the classic beginner&amp;rsquo;s mistake of importing other people&amp;rsquo;s flashcard decks and using those. This year, early in my job hunt (thank goodness!), I decided to ditch the imported decks and start making my own Anki cards: specifically, I started working through the lecture slides from Harvard&amp;rsquo;s &lt;a href="https://harvard-iacs.github.io/2020-CS109A/" target="_blank">CS109A&lt;/a> and &lt;a href="https://harvard-iacs.github.io/2021-CS109B/" target="_blank">CS109B&lt;/a> courses - which I took in 2016 and 2017, respectively. Doing this was a &lt;em>game changer&lt;/em>. In so many ways!&lt;/p>
&lt;p>First, instead of vaguely remembering that, oh yeah, regularization is a thing&amp;hellip; oh, right&amp;hellip; Now I was like a robot that could recite the specific loss function that Lasso and Ridge regressions use.&lt;/p>
&lt;p>Second, as I started &amp;ldquo;putting things in my head&amp;rdquo; (which is what Anki feels like; &amp;ldquo;memory is a choice&amp;rdquo;), I started to get what Nielsen promised: I started seeing connections where I hadn&amp;rsquo;t previously. I developed a deeper intuition. I saw the patterns!&lt;/p>
&lt;p>Third, as I started to &amp;ldquo;know&amp;rdquo; (remember) more and feel more confident and creative with that knowledge, the fixed mindset image of a &amp;ldquo;smart person&amp;rdquo; started to crumble. I&amp;rsquo;ve often been deeply impressed when someone rattles off some random, exotic-to-me mathematical formula. A &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/03/jacobian_stuff/" target="_blank">work colleague saying &amp;ldquo;Jacobian!&amp;rdquo;&lt;/a>. Someone else integrating &lt;code>e&lt;/code> on the fly. Whenever this happened, I would think &amp;ldquo;wow&amp;rdquo; and be both impressed and crushed. I&amp;rsquo;d think, &lt;em>I&amp;rsquo;ll never be that smart.&lt;/em>&lt;/p>
&lt;p>What I didn&amp;rsquo;t realize was: I was defining &amp;ldquo;intelligence&amp;rdquo; as &amp;ldquo;knowledge&amp;rdquo; - as memory - of things I didn&amp;rsquo;t know. No one impressed me if they said something &lt;em>I also remembered&lt;/em>; they impressed me when they said something I thought I &lt;em>should&lt;/em> know, but didn&amp;rsquo;t remember in that moment. And when I started using Anki, and memory became a choice, I realized: I could now choose to remember that as well. And anything else I thought was useful! And Anki is&amp;hellip; a flashcard app! There&amp;rsquo;s no special magic to it. It just leverages how your brain works: flashcards on a schedule to fight against the &lt;a href="https://www.sciencedirect.com/science/article/pii/B9780128196205000199">forgetting curve&lt;/a> .&lt;/p>
&lt;p>The realization that, with &amp;ldquo;one weird trick&amp;rdquo;, I could suddenly &lt;em>know&lt;/em> all of these things&amp;hellip; well, the ceiling of possibilities just went way up. And my life has gotten so much richer. And now I really am, deeply, growth mindset. I think this directly impacted my &lt;em>desire&lt;/em> to get hard interviews. I had a few interviews that were lightweight and easygoing, for roles that nonetheless seemed amazing. Past Angela would have counted her good luck. Current Angela was immensely disappointed, to the point that I worried those roles - even though the teams and projects seemed great - would be &amp;ldquo;too easy&amp;rdquo;. I started telling interviewers this, and really meaning it: I want hard problems. Even the overall &amp;ldquo;basic data science domain&amp;rdquo; - once I completed the Ankification of CS109A and CS109B - seemed&amp;hellip; small? I was like Marlin: &lt;a href="https://www.youtube.com/watch?v=eWXOurnVTYg" target="_blank">&amp;ldquo;3 stripes? that&amp;rsquo;s all I have?&amp;rdquo;&lt;/a>&lt;/p>
&lt;p>Fourth, I am finally going to put linear algebra in my head. FINALLY. And I purely mean an engineer&amp;rsquo;s/craftsperson&amp;rsquo;s toolkit knowledge of linear algebra, not the proofs. Maybe this is foolish. But I&amp;rsquo;m excited.&lt;/p>
&lt;h2 class="relative group">To take-home or not to take-home
&lt;div id="to-take-home-or-not-to-take-home" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#to-take-home-or-not-to-take-home" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Before I became a parent, I loved take-home assignments in hiring processes. I had ample leisure time to work on them! They removed performance anxiety. They felt more &amp;ldquo;honest&amp;rdquo; since, after all, they&amp;rsquo;re a more accurate representation of what working with a person would be like: it is rare for my colleagues to stand over my shoulder, give me a riddle on Coderpad, and then watch me code. It is much more common for us to discuss some problem, often via Slack or standup, and then for me to come back with some Jupyter notebook.&lt;/p>
&lt;p>I still think there&amp;rsquo;s a benefit to take-home assignments - due to that last point above - but I think keen candidates &lt;em>will&lt;/em> spend 2x the recommended time on them. I had three take-home assignments during this job hunt and I spent 7, 3 and 4 hours on them, respectively. I was rejected from the ones I spent more time on. At the time, I thought, well, okay, I probably spend about 7 hours prepping for a code screen. But that&amp;rsquo;s not true anymore. Once I cracked that screen, I basically didn&amp;rsquo;t prep for it. Once I cracked the performance anxiety, I just needed to leverage my existing Python muscle memory. And while a job hunt is, by definition, an enormous amount of energy spent on things that don&amp;rsquo;t materialize, the 7 hours I spent on that one assignment still stand out as&amp;hellip; particularly wasteful of my time. Specifically, I hadn&amp;rsquo;t met anyone on the team yet, had no idea if me and the potential boss would gel well, had no idea what the specific projects I would work on would be. In other words, I was investing a &lt;em>lot&lt;/em> of my time on something that might have ended up not even being a good fit.&lt;/p>
&lt;p>That information asymmetry, coupled with the opportunity cost of my time as a parent, means I&amp;rsquo;ve cooled down a bit on take-home assignments. I still like them when I&amp;rsquo;m the one doing the hiring: they give you good insight into a lot of things - the candidate&amp;rsquo;s enthusiasm for the position, their knowledge, their creativity in applying that knowledge. Even stuff like code style, written communication (I&amp;rsquo;m a big fan of well-written Jupyter notebook Markdown cells.) Also, take-home assignments are standardized (everyone answers the same prompt) and much less subject to the random variation of a bad interviewer, bad day, etc. The whole hiring team can look over and discuss a candidate&amp;rsquo;s assignment at their leisure too.&lt;/p>
&lt;p>Hmm. Okay, well now I&amp;rsquo;ve convinced myself again that take-home assignments are a better option. But maybe a code screen + a case study accomplish much the same differentiation, sacrificing a bit to variance/luck? Either way, I did appreciate when hiring managers stressed, repeatedly, not to take more than X hours on an assignment.&lt;/p>
&lt;h2 class="relative group">Final rounds, interviewing them
&lt;div id="final-rounds-interviewing-them" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#final-rounds-interviewing-them" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The only thing I&amp;rsquo;ll say about the final rounds - which were almost uniformly grueling, given the time investment (usually they were 4-7 hours, spread out over one or two days) - is that this was often the &lt;em>only&lt;/em> opportunity I had to meet more of the people I&amp;rsquo;d be working with. And, thus, to interview them. I do take this seriously, since job offers need to be about a good fit on both sides. As one friend noted, a job hunt is 6 weeks of pain - but being in a &amp;ldquo;wrong fit&amp;rdquo; job can be much more painful and for much longer. So, as much as the emotional rollercoaster (&amp;ldquo;do they like me? they like me! they like me!&amp;rdquo;) sometimes clouded my ability to put the brakes on and ask harder questions, I did try. I had to consciously make an effort. It&amp;rsquo;s worth it!&lt;/p></description></item><item><title>Billion Dollar Loser- The Epic Rise and Spectacular Fall of Adam Neumann and WeWork (2020) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/billion_dollar_loser_the_epic_rise_and_spectacular_fall_of_adam_neumann_and_wework/</link><pubDate>Sun, 27 Mar 2022 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/billion_dollar_loser_the_epic_rise_and_spectacular_fall_of_adam_neumann_and_wework/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/billion_dollar_loser_the_epic_rise_and_spectacular_fall_of_adam_neumann_and_wework/book_jacket_hu434f2c984cb94a938caa3e3a193156f4_51509_330x0_resize_q75_box.jpg 330w,
/posts/billion_dollar_loser_the_epic_rise_and_spectacular_fall_of_adam_neumann_and_wework/book_jacket_hu434f2c984cb94a938caa3e3a193156f4_51509_660x0_resize_q75_box.jpg 660w,
/posts/billion_dollar_loser_the_epic_rise_and_spectacular_fall_of_adam_neumann_and_wework/book_jacket_hu434f2c984cb94a938caa3e3a193156f4_51509_1024x0_resize_q75_box.jpg 1024w,
/posts/billion_dollar_loser_the_epic_rise_and_spectacular_fall_of_adam_neumann_and_wework/book_jacket_hu434f2c984cb94a938caa3e3a193156f4_51509_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/billion_dollar_loser_the_epic_rise_and_spectacular_fall_of_adam_neumann_and_wework/book_jacket_hu434f2c984cb94a938caa3e3a193156f4_51509_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Reeves Wiedeman&lt;/li>
&lt;li>Number of pages: 352&lt;/li>
&lt;li>Year published: 2020&lt;/li>
&lt;li>Year read: 2022&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>A brisk and frisky journalist&amp;rsquo;s account of the, indeed, spectacular fall of WeWork. I have, like many people, used WeWorks. They&amp;rsquo;re fine. They&amp;rsquo;re very Millennial. And Millennials are getting old, people. I&amp;rsquo;m an old Millennial and even my &amp;ldquo;young Millennial&amp;rdquo; friends are using outdated slang. It&amp;rsquo;s not 2012 anymore! &lt;br/>&lt;br/>I wonder what gen Z people think of the WeWork aesthetic, or I guess their offices will be in the metaverse. &lt;br/>&lt;br/>Anyway, I had no idea about Adam Neumann. I had tangentially heard about some of his more egregious &amp;ldquo;crazy billionaire&amp;rdquo; antics. This book was&amp;hellip; wow. I hoovered it up in one sitting. The schadenfreude was, agh, chef&amp;rsquo;s kiss. Very enjoyable. You gotta read it to believe it. In Neumann&amp;rsquo;s defense, he&amp;rsquo;s just a symptom of a crazy system right now - VCs, startups, etc.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/54502643" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Nice bash tchotchkes</title><link>https://www.angelaambroz.com/posts/nice_bash_tchotchkes/</link><pubDate>Tue, 21 Sep 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/nice_bash_tchotchkes/</guid><description>&lt;p>Hello! Some nice things I&amp;rsquo;ve been using lately:&lt;/p>
&lt;h2 class="relative group">&lt;a href="https://github.com/ajeetdsouza/zoxide" target="_blank">&lt;code>zoxide&lt;/code>&lt;/a>: Smarter &lt;code>cd&lt;/code>
&lt;div id="zoxidehttpsgithubcomajeetdsouzazoxide-smarter-cd" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#zoxidehttpsgithubcomajeetdsouzazoxide-smarter-cd" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://github.com/ajeetdsouza/zoxide" target="_blank">&lt;code>zoxide&lt;/code>&lt;/a> is great - it keeps a &amp;ldquo;memory&amp;rdquo; of the directories you&amp;rsquo;ve been in and, once you&amp;rsquo;ve visited them, you can revisit them using something like &lt;code>z blog&lt;/code> and it&amp;rsquo;ll jump you to whichever recent directory had &lt;code>blog&lt;/code> in the path. Much, &lt;em>much&lt;/em> more streamlined than &lt;code>cd /some/super/long/path&lt;/code>, or making a bunch of aliases for such &lt;code>cd&lt;/code>s (as I have done in the past).&lt;/p>
&lt;h2 class="relative group">&lt;a href="https://github.com/cantino/mcfly" target="_blank">&lt;code>mcfly&lt;/code>&lt;/a>: Smarter reverse-search
&lt;div id="mcflyhttpsgithubcomcantinomcfly-smarter-reverse-search" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#mcflyhttpsgithubcomcantinomcfly-smarter-reverse-search" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Same deal as above: you type &lt;code>ctrl+r&lt;/code> and it launches a smarter search window of your old commands. HANDY.&lt;/p>
&lt;h2 class="relative group">Prompt colors
&lt;div id="prompt-colors" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#prompt-colors" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I wanted to bedazzle my prompt, own it, express my - ahem - creative individuality. Also I wanted to fem it up. I use the &lt;a href="https://github.com/sindresorhus/pure" target="_blank">&lt;code>pure&lt;/code>&lt;/a> theme for &lt;a href="https://zsh.sourceforge.io/" target="_blank">&lt;code>zsh&lt;/code>&lt;/a>, and it was as easy as adding this to my &lt;code>~/.zshrc&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">prompt pure
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">zstyle :prompt:pure:path color &lt;span class="s2">&amp;#34;#af87d7&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">zstyle :prompt:pure:prompt:success color &lt;span class="s2">&amp;#34;#af87d7&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Irresistible- The Rise of Addictive Technology and the Business of Keeping Us Hooked (2017) -</title><link>https://www.angelaambroz.com/posts/irresistible_the_rise_of_addictive_technology_and_the_business_of_keeping_us_hooked/</link><pubDate>Thu, 22 Apr 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/irresistible_the_rise_of_addictive_technology_and_the_business_of_keeping_us_hooked/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/irresistible_the_rise_of_addictive_technology_and_the_business_of_keeping_us_hooked/book_jacket_hucfba578f7f054239ea156b09175b51cb_34930_330x0_resize_q75_box.jpg 330w,
/posts/irresistible_the_rise_of_addictive_technology_and_the_business_of_keeping_us_hooked/book_jacket_hucfba578f7f054239ea156b09175b51cb_34930_660x0_resize_q75_box.jpg 660w,
/posts/irresistible_the_rise_of_addictive_technology_and_the_business_of_keeping_us_hooked/book_jacket_hucfba578f7f054239ea156b09175b51cb_34930_1024x0_resize_q75_box.jpg 1024w,
/posts/irresistible_the_rise_of_addictive_technology_and_the_business_of_keeping_us_hooked/book_jacket_hucfba578f7f054239ea156b09175b51cb_34930_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/irresistible_the_rise_of_addictive_technology_and_the_business_of_keeping_us_hooked/book_jacket_hucfba578f7f054239ea156b09175b51cb_34930_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Adam Alter&lt;/li>
&lt;li>Number of pages: 368&lt;/li>
&lt;li>Year published: 2017&lt;/li>
&lt;li>Year read: 2021&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>He&amp;rsquo;s preaching to the choir here, but I couldn&amp;rsquo;t get past the long, looong intro on &amp;ldquo;addiction is a thing&amp;rdquo;. Yes, it is. Yep, cocaine. Yep, lab rats pressing pleasure buttons until they die. I thought we&amp;rsquo;d get to the tech addictiveness-by-design a lot sooner. I ended up putting this down and never feeling like picking it up again.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/30962055" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>My own private server</title><link>https://www.angelaambroz.com/posts/my_own_private_server/</link><pubDate>Sun, 11 Apr 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/my_own_private_server/</guid><description>&lt;p>Big changes in 2021, beyond &lt;a href="http://angelaambroz.com/blog/posts/2021/Apr/02/linux_first_impressions/" target="_blank">Linux&lt;/a>. Yeah, boy. We&amp;rsquo;re getting serious about computers, man. I shelled out the cash for a network-attached storage (NAS) device, AKA a tiny little cloud that lives in our home. Thrilled with this. Thrilled!&lt;/p>
&lt;h2 class="relative group">Our use cases
&lt;div id="our-use-cases" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#our-use-cases" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h3 class="relative group">1. Consolidated data backup
&lt;div id="1-consolidated-data-backup" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#1-consolidated-data-backup" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Like most people (I assume), we were backing up our data in a number of places:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>External solid state drives&lt;/strong> for when you&amp;rsquo;re like &amp;ldquo;okay, I should really &lt;em>back. up. this. computer.&lt;/em> I hadn&amp;rsquo;t used my SSD to backup in 700+ days, my Macbook Time Machine helpfully screamed at me. Yeah, manual backing up is hard. Also, the SSDs had random other things we kinda needed but didn&amp;rsquo;t have space to put anywhere else - photos, movies.&lt;/li>
&lt;li>&lt;strong>Various big tech cloud services (Google, Dropbox)&lt;/strong>. Automated backing up: so easy! So nice. Not free, of course. And&amp;hellip; it&amp;rsquo;s on their servers. Which I have been increasingly uncomfortable with. Stop scanning my loved ones&amp;rsquo; faces for your machine learning, Google! I knew I wanted to stop trading privacy for convenience.&lt;/li>
&lt;/ul>
&lt;p>The NAS offers one big helpful block of storage space. We can backup automatically. We can connect it to a secure (single!) off-site server for one consolidated stream of our crap. Yessss.&lt;/p>
&lt;h3 class="relative group">2. Media server
&lt;div id="2-media-server" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#2-media-server" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>I didn&amp;rsquo;t think I&amp;rsquo;d enjoy this aspect so much but &lt;em>oh boy, have I been enjoying this&lt;/em>. I installed &lt;a href="https://www.plex.tv/" target="_blank">Plex&lt;/a> on our NAS, uploaded all our old movies and TVs and eeeeeee, now we can actually watch them! And they&amp;rsquo;re beautifully organized! Eeeee. And we can set up user accounts and even, if we&amp;rsquo;re willing to accept the security risk of opening the NAS up to the wild, hairy open internet, we could stream it remotely. Our own private Netflix! Eeeeee. Now I need to rip all our old DVDs and yaaaaas.&lt;/p>
&lt;h3 class="relative group">3. Photos
&lt;div id="3-photos" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#3-photos" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>I really, &lt;em>really&lt;/em> was getting annoyed with how entangled with Google I was getting. And the main entanglement was via photos of loved ones (of which I have, apparently, 11k!). I&amp;rsquo;m not a photographer. I just take a bajillion pictures because my pocket computer surveillance device makes it soooo easy. We have a Synology NAS and, using their native app, &lt;a href="https://www.synology.com/en-us/dsm/feature/moments" target="_blank">Synology Moments&lt;/a>, I&amp;rsquo;ve been able to (a) automagically backup all the 11k loved one pics offloaded from my phone and (b) do the facial recognition thing to sort them into Specific Loved Ones. The latter is not as good as Google&amp;rsquo;s, I&amp;rsquo;m feeling, but it&amp;rsquo;s good enough. And privacy + good enough &amp;gt; no_privacy + slightly better.&lt;/p>
&lt;p>In fact, a &lt;strong>note to current/future Synology users&lt;/strong>: I followed a tutorial which advised me to use &lt;a href="https://takeout.google.com/" target="_blank">Google Takeout&lt;/a> to manually export all my Google Photos data into 60+ (!) 2GB .zip files which I then started laboriously unzipping and moving to the NAS manually. Why. WHYY. The Synology Moments Android app just automagically backed all those 11k pics up. So&amp;hellip; do that instead.&lt;/p></description></item><item><title>Linux, first impressions</title><link>https://www.angelaambroz.com/posts/linux_first_impressions/</link><pubDate>Fri, 02 Apr 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/linux_first_impressions/</guid><description>&lt;p>This year was personal laptop rollover year, and I was excited to finally take the plunge: Linux! Yes, Linux. After polling some dev bros and doing a lot of YouTube research, I ended up replacing my 2015 MacBook Pro with a &lt;a href="https://system76.com/laptops/lemur" target="_blank">System76 Lemur Pro (specifically, the &lt;code>lemp10&lt;/code>)&lt;/a>. With that new hardware came a whole new operating system: &lt;a href="https://pop.system76.com/" target="_blank">Pop!_OS&lt;/a>. I&amp;rsquo;ve now had the new machine for a few days, and I want to record my initial thoughts/feelings with this brave new FOSS world.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Motivation
&lt;div id="motivation" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#motivation" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I grew up using Windows machines. In 2010, I switched to MacBook Pros, both for work and for home. I&amp;rsquo;ve been thinking about switching to Linux ever since &lt;a href="https://lifehacker.com/im-cory-doctorow-and-this-is-how-i-work-5993401" target="_blank">this article about Cory Doctorow&amp;rsquo;s workflow came out in 2013&lt;/a>, but lots of stuff held me back. I kept a spreadsheet of all the Mac apps I thought I needed that Linux wouldn&amp;rsquo;t have - Evernote, Microsoft Office (this was in my &lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/04/journey_to_the_center_of_data_science/" target="_blank">pre-career transition&lt;/a> days). Finally - in 2021 (!) - my life is now programmy enough that moving to Linux seemed sensible and fine. In particular, I was really inspired by this entry in the always-fun series, &lt;a href="https://usesthis.com/" target="_blank">Uses This&lt;/a>: &lt;a href="https://usesthis.com/interviews/katherine.cox-buday" target="_blank">Katherine Cox-Buday&amp;rsquo;s work setup&lt;/a>. And the fact that a bunch of my work colleagues used Linux at work. And&amp;hellip; a lot of things!&lt;/p>
&lt;p>In fact, here&amp;rsquo;s my motivation list.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>I have been getting more and more sick of &lt;a href="https://en.wikipedia.org/wiki/Planned_obsolescence" target="_blank">planned obsolescence&lt;/a>&lt;/strong>. In an age of climate change and environmental degradation, spurred by a ravenously materialistic culture, it feels especially stupid to make something as dazzling and hard as a COMPUTER - with fancy rare Earth parts and feats of engineering and logic - only to have it be a 2-year social media browser. My MacBook 2010 chugged along well enough until 2015. My 2015 MacBook has been declining slowly for the last year or two. My 2017 work MacBook Pro died spectacularly after 2.5 years&amp;hellip; because the battery fritzed. A battery that is soldered and therefore not replaceable. As an economist, I understand the model: you don&amp;rsquo;t make tons of money by selling people something they need every 10 years (water heaters!). You need to keep that consumption happening. Also, as a &lt;em>macroeconomist&lt;/em>, you need that GDP growing growing growing. &lt;a href="https://www.goodreads.com/book/show/51014619-good-economics-for-hard-times" target="_blank">The 2019 Nobel laureates had something to say about that&amp;hellip;&lt;/a> Anyway, no no no.&lt;/li>
&lt;li>&lt;strong>Speaking of which, why can&amp;rsquo;t I just remove my dead battery?&lt;/strong> Or upgrade my RAM? Or just open it and learn about it and fiddle with it? Why is customization artificially locked away via glued and soldered parts?&lt;/li>
&lt;li>&lt;strong>I want to learn about computers!&lt;/strong> As my life and career has gotten more programmy, I&amp;rsquo;ve become more curious (and more empowered) about different aspects of the computer. My tldr understanding of Linux was: this is an OS that makes you work a bit more - there&amp;rsquo;s more learning curve - but you get rewarded with a deeper understanding of your machine. We&amp;rsquo;ll see indeed if this is true!&lt;/li>
&lt;li>&lt;strong>I could do everything I needed in Linux anyway&lt;/strong>. As an economist, I used Microsoft Word and Excel a lot. As a data scientist, I&amp;rsquo;m mostly working in Jupyter notebooks and vim now (&lt;a href="http://angelaambroz.com/blog/posts/2020/Dec/03/Vim/" target="_blank">glorious vim&lt;/a>).&lt;/li>
&lt;li>&lt;strong>The Pi felt like a breakthrough&lt;/strong>. I don&amp;rsquo;t know why, but &lt;a href="http://angelaambroz.com/blog/posts/2021/Feb/28/setting_up_the_pihole_finally/" target="_blank">setting up my first Raspberry Pi&lt;/a> also loosened me up from my &amp;ldquo;chained to MacBooks&amp;rdquo; feeling.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 class="relative group">Moving from macOS to Pop!_OS
&lt;div id="moving-from-macos-to-pop_os" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#moving-from-macos-to-pop_os" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Much has changed! Oh, the many hours I have spent either (a) in a terminal, (b) accidentally right-clicking, and/or (c) pressing the wrong keyboard shortcut. Ay, it has been a little painful, a little joyous. I think things are a bit more settled now, after that initial shock. My report!&lt;/p>
&lt;h3 class="relative group">First, and most importantly: all the keyboard shortcuts are weird
&lt;div id="first-and-most-importantly-all-the-keyboard-shortcuts-are-weird" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#first-and-most-importantly-all-the-keyboard-shortcuts-are-weird" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Arrghh. Keyboard shortcuts. After 10 years, I am a wizard at text editing and dashing around with &lt;code>cmd&lt;/code> this and 3-/4-finger gesture that. Pop!_OS dropped me into a new world where keyboard shortcuts that had been unified under a macOS&amp;rsquo;s &lt;code>cmd&lt;/code> were now living under three new keys: &lt;code>ctrl&lt;/code>, &amp;ldquo;&lt;code>Super&lt;/code>&amp;rdquo; (a System76-specific special key), and &lt;code>alt&lt;/code>. Aieee. My pinkyyyyy.&lt;/p>
&lt;p>This has taken, of course, some MASSIVE getting used to, as well as onerous pecking and mousing/clicking in the earliest hours. I have since discovered the general rule that: (1) &lt;code>Super&lt;/code> for &amp;ldquo;big stuff&amp;rdquo; (launching/quitting apps, moving across workspaces), &lt;code>ctrl&lt;/code> for ye olde stuff (closing browser tabs, jumping forward/backward words), and &lt;code>alt&lt;/code> as a wild card (jumping across browser tabs? reloading the previous or the future page?).&lt;/p>
&lt;p>All a little unexpected and painful, and I&amp;rsquo;ve seen that Pop!_OS natively supports some vim movements for things. MAYBE I CAN MAKE IT ALL VIM!?&lt;/p>
&lt;h3 class="relative group">Replicating macOS trackpad gestures
&lt;div id="replicating-macos-trackpad-gestures" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#replicating-macos-trackpad-gestures" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Which brings us to the next big thing I do with my hands (&lt;a href="https://www.youtube.com/watch?v=s_UVPLHAOAY" target="_blank">&amp;ldquo;prehensile paws&amp;rdquo;&lt;/a>): TRACKPAD STUFF. Namely, macOS&amp;rsquo;s glorious gestures - which I fell in love with in 2010 and, honestly, were another big reason I was hesitant to switch to Linux.&lt;/p>
&lt;p>This was actually &lt;em>very&lt;/em> easy. Almost trivial? I mean, I spent an hour or two researching and installing and so on, but - once I found what I wanted - it was really straightforward. And suddenly, that whole gesturey aspect was unlocked.&lt;/p>
&lt;p>Basically, I&amp;rsquo;m using &lt;a href="https://github.com/bulletmark/libinput-gestures" target="_blank">&lt;code>libinput-gestures&lt;/code>&lt;/a>, a (mostly-)Python library that interprets the touchpad gestures and maps them to shell commands. Out of the box, using the default configuration, it replicated the 3-gesture workspace swipe that I&amp;rsquo;ve grown so accustomed to.&lt;/p>
&lt;h3 class="relative group">RTFM
&lt;div id="rtfm" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#rtfm" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Actually, in installing &lt;code>libinput-gestures&lt;/code>, I ran into a workflow that I&amp;rsquo;ve been using for years now and I just &lt;em>know&lt;/em> is not serving me well. It serves me maybe 70% well. Basically, when I don&amp;rsquo;t know how to do something, especially something programmy, especially something about installing a package via the shell, I normally:&lt;/p>
&lt;ul>
&lt;li>DuckDuckGo it.&lt;/li>
&lt;li>Find the first answer that seems relevant.&lt;/li>
&lt;li>Scan, without reading, for the first code block.&lt;/li>
&lt;li>Copy+paste whatever is in that code block and see if that works.&lt;/li>
&lt;/ul>
&lt;p>Yes, I know. Hackers, here&amp;rsquo;s your entry point! Just stick a fake search result in a&amp;hellip; Well, anyway.&lt;/p>
&lt;p>So the worst thing about this is that &lt;em>it does work&lt;/em>, like maybe 60% of the time. And so I&amp;rsquo;m being randomly dopamine-rewarded for a very bad process indeed. With the above, when I was installing &lt;code>libinput-gestures&lt;/code> (which has very good documentation), I faced an easy problem and kept opening more and more search tabs, trying random things, shaving yaks randomly, before finally finding the solution&amp;hellip; in the README. A solution that had been clearly written in both the project&amp;rsquo;s GitHub README &lt;em>and&lt;/em> in the config file I was struggling with.&lt;/p>
&lt;p>I&amp;rsquo;ve noticed this happening in other ways, but, really, I should just RTFM. It seems more &amp;ldquo;costly&amp;rdquo; up front, but I can likely spare myself a lot of browser tabs and hand-waving.&lt;/p>
&lt;h3 class="relative group">How could someone survive without the shell?
&lt;div id="how-could-someone-survive-without-the-shell" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-could-someone-survive-without-the-shell" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>So far, I&amp;rsquo;ve spent many a happy hour installing, debugging, and generally fiddling with things in the Pop!_OS terminal. (Which is called Terminal?) This is fine and well, and I feel confident enough to do what I need to do. But what if the Terminal is strange to you? There do seem to be a lot of Linux GUI things floating around, and maybe they&amp;rsquo;re sufficient? But it seemed like everything I ran into (e.g. &lt;code>libinput-gestures&lt;/code>) assumed some familiarity with the command line. I would have struggled much more in 2013. I do wonder about this. How do non-command line users experience and enjoy Linux? I&amp;rsquo;m so curious, I might investigate this and see if there&amp;rsquo;s any blog posts, etc.&lt;/p>
&lt;h3 class="relative group">Everything is a choice
&lt;div id="everything-is-a-choice" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#everything-is-a-choice" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>This is both the blessing and curse. I didn&amp;rsquo;t like the way Pop!_OS&amp;rsquo;s default file browser looked and worked. I understood that, with Linux, I could change this. Oh man, and cue the Reddit threads and browsing of &lt;code>.deb&lt;/code>s and &lt;code>.flatpak&lt;/code>s (what are these?) and all that. I ended up with &lt;a href="https://en.wikipedia.org/wiki/Nemo_%28file_manager%29" target="_blank">Nemo&lt;/a>, since it was vaguely pretty and immediately intuitive.&lt;/p>
&lt;h3 class="relative group">Speaking of pretty&amp;hellip;
&lt;div id="speaking-of-pretty" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#speaking-of-pretty" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Default macOS is very pretty. So stylish. So Just Works-y. So confidence-building. Linux is definitely a little uglier, harsher, etc. I mean, I love the form factor (NEW WORD I LEARNED) of my beautiful, featherweight Lemur Pro. And the&amp;hellip; KDE (?) - the windows, the dock (oh yeah, &lt;a href="https://support.system76.com/articles/dash-to-dock/" target="_blank">I installed and replicated the macOS dock&lt;/a>) are certainly charmingly okay. But I will work on beautifying this machine.&lt;/p>
&lt;h2 class="relative group">Further reading
&lt;div id="further-reading" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#further-reading" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=jowCUo_UGts" target="_blank">Unix vs Linux, &lt;em>Gary Explains&lt;/em>&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=26QPDBe-NB8" target="_blank">Operating Systems: Crash Course Computer Science #18, &lt;em>CrashCourse&lt;/em>&lt;/a>
&lt;ul>
&lt;li>&lt;a href="https://clas.ucdenver.edu/fast/sites/default/files/attached-files/computer_science_crash_course_annotations_28september2020_final.pdf" target="_blank">&amp;hellip;with an annotated user&amp;rsquo;s guide from the University of Colorado - Denver?&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://linuxcommand.org/tlcl.php" target="_blank">&lt;em>Linux Command Line&lt;/em>, William Shotts&lt;/a> (free)&lt;/li>
&lt;li>&lt;a href="https://nostarch.com/howlinuxworks3" target="_blank">&lt;em>How Linux Works (3rd edition, 2021)&lt;/em>, Brian Ward&lt;/a> (not free)&lt;/li>
&lt;/ul></description></item><item><title>In praise of exercism.io</title><link>https://www.angelaambroz.com/posts/in_praise_of_exercismio/</link><pubDate>Thu, 01 Apr 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/in_praise_of_exercismio/</guid><description>&lt;p>I began &amp;ldquo;learning to code&amp;rdquo; in 2014, where by &amp;ldquo;learning to code&amp;rdquo;, I mean moving away from &lt;a href="https://www.stata.com/" target="_blank">Stata&lt;/a> (a proprietary statistical programming language) and into &lt;a href="https://d3js.org/" target="_blank">d3.js&lt;/a>, &lt;a href="https://www.javascript.com/" target="_blank">JavaScript&lt;/a> more generally, and, finally, glorious &lt;a href="https://www.python.org/" target="_blank">Python&lt;/a>. You can read the whole journey &lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/04/journey_to_the_center_of_data_science/" target="_blank">here&lt;/a>.&lt;/p>
&lt;p>Anyway, back in 2014, I found a number of fun, puzzle-driven coding practice websites. Among these were:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.hackerrank.com/" target="_blank">HackerRank&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://leetcode.com/" target="_blank">LeetCode&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://adventofcode.com/" target="_blank">Advent of Code&lt;/a>&lt;/li>
&lt;li>and &lt;a href="https://exercism.io/" target="_blank">Exercism&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Since getting off the ground with the basics, I&amp;rsquo;ve periodically returned to these - mostly LeetCode - but never for very long stretches. I just spent some time working through Exercism though and (a) it&amp;rsquo;s changed a lot, (b) in a really good way.&lt;/p>
&lt;h2 class="relative group">Why is it so nice?
&lt;div id="why-is-it-so-nice" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#why-is-it-so-nice" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;m really enjoying it! It&amp;rsquo;s so nice! There&amp;rsquo;s a bunch of nice&amp;hellip; nicenesses about it.&lt;/p>
&lt;ol>
&lt;li>First, the aesthetic is inclusive and diverse. They make a point of showing a wide range of humans coding.&lt;/li>
&lt;li>The &lt;a href="https://exercism.io/cli" target="_blank">command line interface&lt;/a> is lightweight and friendly. You can easily download puzzles and submit solutions.&lt;/li>
&lt;li>There are numerous language tracks available. I&amp;rsquo;ve signed up for Python, Clojure (&lt;a href="http://angelaambroz.com/blog/tag/clojure.html" target="_blank">good ol&amp;rsquo; Clojure&lt;/a>), Go, and bash.&lt;/li>
&lt;li>The puzzles emphasize teaching the language and its idioms, rather than grinding &lt;a href="https://www.crackingthecodinginterview.com/" target="_blank">CTCI&lt;/a>-style riddles. I still think HackerRank and LeetCode might be quite good places to grind your understanding of algorithms and data structures (and thus high-level coding interviews), but Exercism is more about becoming a master craftsperson for its own sake. You get to know the language in a lower-pressure, friendly way.&lt;/li>
&lt;li>The CLI, interacted with the different languages you&amp;rsquo;d like to learn (e.g. Clojure), means you can set up your own local environment (figuring out both how to do it, and what you like).&lt;/li>
&lt;li>You &lt;em>see the tests&lt;/em>. This is not the case with LeetCode, iirc, which hides the tests but lets you &amp;ldquo;unlock&amp;rdquo; different test cases for $$$. Oof. Exercism is free and you can, well, teach yourself to the test. This has been a nice way for me to think about edge cases (&amp;ldquo;oh yeah, good point, test file&amp;rdquo;) and address them.&lt;/li>
&lt;li>After submitting your solution, you can seek a &amp;ldquo;Mentor&amp;rsquo;s&amp;rdquo; advice (I haven&amp;rsquo;t done this yet) and/or peruse other people&amp;rsquo;s solutions (I have done this). I&amp;rsquo;ve really enjoyed the latter because often you learn a nice idiomatic way to do something.&lt;/li>
&lt;li>The &amp;ldquo;easy&amp;rdquo; puzzles are bite-sized snacks, good for when you&amp;rsquo;re waiting for a meeting to start&amp;hellip;&lt;/li>
&lt;/ol>
&lt;h2 class="relative group">Overall, highly recommend!
&lt;div id="overall-highly-recommend" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#overall-highly-recommend" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Great job, Exercism community!&lt;/p></description></item><item><title>Some shell magic</title><link>https://www.angelaambroz.com/posts/some_shell_magic/</link><pubDate>Wed, 31 Mar 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/some_shell_magic/</guid><description>&lt;p>I just ran:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">find * -type f -exec &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;{}&amp;#34;&lt;/span> &lt;span class="se">\;&lt;/span> -exec awk &lt;span class="s2">&amp;#34;NR==26&amp;#34;&lt;/span> &lt;span class="o">{}&lt;/span> &lt;span class="se">\;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Which I adapted &lt;a href="https://stackoverflow.com/questions/8512462/looping-through-all-files-in-a-directory" target="_blank">from this StackOverflow post&lt;/a> and, tldr, searches all files in my current directory (and subdirectories) and tells me what&amp;rsquo;s written on line 26.&lt;/p>
&lt;p>Or, parsing it out:&lt;/p>
&lt;ul>
&lt;li>&lt;code>find&lt;/code>: &amp;ldquo;Find files or directories under the given directory tree, recursively.&amp;rdquo; ( - &lt;a href="https://tldr.sh/" target="_blank">tldr&lt;/a>)&lt;/li>
&lt;li>&lt;code>*&lt;/code>: Anything in the current directory.&lt;/li>
&lt;li>&lt;code>-type f&lt;/code>: A file (not a directory).&lt;/li>
&lt;li>&lt;code>-exec&lt;/code>: A flag in &lt;code>find&lt;/code> which will run a shell command. If you include &lt;code>{}&lt;/code> in that shell command, it will replace it with the &amp;ldquo;found&amp;rdquo; filename (or directory).&lt;/li>
&lt;li>&lt;code>echo&lt;/code>: Print to &lt;code>stdout&lt;/code>.&lt;/li>
&lt;li>&lt;code>&amp;quot;{}&amp;quot;&lt;/code>: The current filename.&lt;/li>
&lt;li>&lt;code>\;&lt;/code>: End of that command.&lt;/li>
&lt;li>&lt;code>-exec&lt;/code>: Yo, you can chain these guys!&lt;/li>
&lt;li>&lt;code>awk&lt;/code>: &amp;ldquo;A versatile programming language for working on files.&amp;rdquo; ( - &lt;a href="https://tldr.sh/" target="_blank">tldr&lt;/a>) AKA, magic.&lt;/li>
&lt;li>&lt;code>&amp;quot;NR==26&amp;quot;&lt;/code>: Magic syntax. Found this via StackOverflow. Line number 26.&lt;/li>
&lt;li>&lt;code>{}&lt;/code>: The current filename (still coming from the &lt;code>find&lt;/code> command).&lt;/li>
&lt;li>&lt;code>\;&lt;/code>: The end.&lt;/li>
&lt;/ul>
&lt;p>It outputs something like:&lt;/p>
&lt;pre tabindex="0">&lt;code>file1.txt
README.md
some_subdirectory/file2.txt
some random text on line 26
some_subdirectory/file3.txt
.some_config_file
enabled: true
&lt;/code>&lt;/pre>&lt;p>&lt;em>Cool!&lt;/em>&lt;/p></description></item><item><title>dwebp</title><link>https://www.angelaambroz.com/posts/dwebp/</link><pubDate>Thu, 25 Mar 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/dwebp/</guid><description>&lt;p>A small, short tutorial today: &lt;b>How to convert those darn &lt;code>.webp&lt;/code> files into &lt;code>.jpg&lt;/code>?&lt;/b>&lt;/p>
&lt;h2 class="relative group">Motivation
&lt;div id="motivation" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#motivation" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>If you, like me, periodically refresh your Zoom background to something fun and festive, you too may run into the dreaded new Internet image format: &lt;code>.webp&lt;/code>. This is a &lt;a href="https://developers.google.com/speed/webp" target="_blank">Google-developed image format&lt;/a> which is a bit more efficient in compressing images for the Web, with less quality loss. Unfortunately, while they load in a webpage fine, my Preview app was not recognizing them. What&amp;rsquo;s a saving-images-from-the-Internet-person to do?&lt;/p>
&lt;h2 class="relative group">Example and 2 okay solutions
&lt;div id="example-and-2-okay-solutions" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#example-and-2-okay-solutions" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Consider this image, from &lt;a href="https://www.reddit.com/r/zoombackgrounds/" target="_blank">r/ZoomBackgrounds&lt;/a>: &lt;a href="https://preview.redd.it/1coyps2tmlo61.jpg?width=1920&amp;amp;format=pjpg&amp;amp;auto=webp&amp;amp;s=540ed8b25ca5ba00540a158759239d8f8c49e7d3" target="_blank">image link&lt;/a>&lt;/p>
&lt;p>If you right-click and &lt;code>Save Image As...&lt;/code>, your only option is to save it as a &lt;code>WebP Image&lt;/code>. While &lt;a href="https://www.youtube.com/watch?v=8xqUUsflpxc" target="_blank">this YouTube video&lt;/a> shows how you can trim everything after &lt;code>jpg?&lt;/code> from the URL, this may not work. If you try it on the above link, you&amp;rsquo;ll get a &lt;code>403 Forbidden&lt;/code>.&lt;/p>
&lt;p>Another solution, which did work for me, but felt very 2003 &amp;ldquo;I have no idea how to computer&amp;rdquo;, was this dodgy website which lets you upload your &lt;code>.webp&lt;/code> files and re-download them as &lt;code>.jpg&lt;/code>s. I won&amp;rsquo;t bother linking, you can Google/DuckDuckGo that yourself. Since I have no idea what chicanery is happening behind the scenes of such a website.&lt;/p>
&lt;h2 class="relative group">Best solution: The command line!
&lt;div id="best-solution-the-command-line" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#best-solution-the-command-line" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>DuckDuckGo-ing &amp;ldquo;webp jpg command line&amp;rdquo; delivered me unto &lt;a href="https://developers.google.com/speed/webp" target="_blank">the Google docs&lt;/a>, and, lo, there is a simple, Homebrew-installable command line utility that will do the converting for you.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">brew install webp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">dwebp calvin.webp -o calvin.jpg
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Voila! That worked. Much easier. Much more transparent-feeling. Note that the &lt;a href="https://formulae.brew.sh/formula/webp" target="_blank">&lt;code>webp&lt;/code> Homebrew formula&lt;/a> downloads several utilities:&lt;/p>
&lt;ul>
&lt;li>&lt;code>cwebp&lt;/code>: For encoding from &lt;code>.jpg&lt;/code> -&amp;gt; &lt;code>.webp&lt;/code>. I guess if you&amp;rsquo;re a web developer?&lt;/li>
&lt;li>&lt;code>dwebp&lt;/code>: For decoding your Calvin &amp;amp; Hobbes backgrounds back to &lt;code>.jpg&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>And other stuff, including one utility called &lt;code>webpmux&lt;/code>, which the docs helpfully describe as a &amp;ldquo;WebP muxing tool&amp;rdquo;. What in the world is muxing? (Apparently &lt;a href="https://en.wikipedia.org/wiki/Multiplexing" target="_blank">combining multiple analog/digital signals into one&lt;/a>. Still have no idea what that means.)&lt;/p>
&lt;h2 class="relative group">Endnotes
&lt;div id="endnotes" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#endnotes" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Here&amp;rsquo;s German 1920s-revival singer Max Raabe and German rapper Samy Deluxe singing one of my favorites, &lt;i>Der perfekte Moment&lt;/i>. A true ode to laziness!&lt;/p>
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/1tqKeIOQbFM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen>&lt;/iframe>
&lt;p>Happy zooming!&lt;/p></description></item><item><title>The Soul of a New Machine (2000) -</title><link>https://www.angelaambroz.com/posts/the_soul_of_a_new_machine/</link><pubDate>Mon, 22 Mar 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/the_soul_of_a_new_machine/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/the_soul_of_a_new_machine/book_jacket_hu9fee40a52592a7bc2f24cd963c0132e0_5625_330x0_resize_q75_box.jpg 330w,
/posts/the_soul_of_a_new_machine/book_jacket_hu9fee40a52592a7bc2f24cd963c0132e0_5625_660x0_resize_q75_box.jpg 660w,
/posts/the_soul_of_a_new_machine/book_jacket_hu9fee40a52592a7bc2f24cd963c0132e0_5625_1024x0_resize_q75_box.jpg 1024w,
/posts/the_soul_of_a_new_machine/book_jacket_hu9fee40a52592a7bc2f24cd963c0132e0_5625_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/the_soul_of_a_new_machine/book_jacket_hu9fee40a52592a7bc2f24cd963c0132e0_5625_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Tracy Kidder&lt;/li>
&lt;li>Number of pages: 293&lt;/li>
&lt;li>Year published: 2000&lt;/li>
&lt;li>Year read: 2021&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Disappointingly Basic Tech Bro-ey. I thought this would be a bit more like &amp;ldquo;Halt and Catch Fire&amp;rdquo;. Oh well.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/7090" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Pi project</title><link>https://www.angelaambroz.com/posts/pi_project_2_indoor_environment_monitor/</link><pubDate>Mon, 08 Mar 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/pi_project_2_indoor_environment_monitor/</guid><description>
&lt;h2 class="relative group">Motivation
&lt;div id="motivation" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#motivation" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>It is winter. The air is dry. Beyond slathering my face in Burt&amp;rsquo;s Bees, we have mostly suffered in this dryness. I am anti-humidifier. They seem like diva equipment. And who wants to clean them weekly? Ugh. But no more! It is time. Also, my &lt;a href="http://angelaambroz.com/blog/posts/2021/Feb/28/setting_up_the_pihole_finally/" target="_blank">last Pi project&lt;/a> broke important barriers in my brain - mostly emotional - and now it seems much easier to try new Pi things. Also also, I had another Pi lying around.&lt;/p>
&lt;h2 class="relative group">Hardware setup
&lt;div id="hardware-setup" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#hardware-setup" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>For this project, I used:&lt;/p>
&lt;ul>
&lt;li>a &lt;a href="https://www.adafruit.com/product/3055" target="_blank">Raspberry Pi 3 - Model B&lt;/a>&lt;/li>
&lt;li>the &lt;a href="https://www.adafruit.com/product/4455" target="_blank">Pimoroni Enviro pHat&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Note&lt;/strong>: I was &lt;strong>unable&lt;/strong> to use the Raspberry Pi 3b case that comes with &lt;a href="https://www.canakit.com/raspberry-pi-3-model-b-plus-starter-kit.html" target="_blank">this CanaKit kit&lt;/a> - the Enviro pHat doesn&amp;rsquo;t fit under the case&amp;rsquo;s middle layer. Word to the wise!&lt;/p>
&lt;h2 class="relative group">Software setup
&lt;div id="software-setup" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#software-setup" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This was a bit of a journey.&lt;/p>
&lt;p>First, I downloaded the latest version of the &lt;a href="https://www.raspberrypi.org/software/operating-systems/" target="_blank">Raspberry Pi operating system&lt;/a> - specifically, the Raspberry Pi OS with desktop. I flashed it onto the micro-SD card using &lt;a href="https://www.balena.io/etcher/" target="_blank">balenaEtcher&lt;/a>. After inserting that SD card into the Pi, as well as attaching all the peripherals (monitor, keyboard, mouse, power), I powered it on and then shaved the yak that is installing everything. At the end of this part of the journey, you have a perfectly serviceable little Linux desktop that I believe all children around 5 years old should have. Free Pis for all kids!&lt;/p>
&lt;p>Second, well&amp;hellip; I spent a lot of time being ridiculous and tinkering with the shell and dotfiles of the Pi. I just want a comfortable programming environment, dammit! This meant first copying over my &lt;a href="https://github.com/angelaambroz/.dotfiles/blob/main/system/.vimrc" target="_blank">&lt;code>.vimrc&lt;/code>&lt;/a>&amp;hellip; and then just going whole hog and copying over all my &lt;a href="https://github.com/angelaambroz/.dotfiles" target="_blank">.dotfiles&lt;/a>, installing &lt;code>zsh&lt;/code> (z-shell), installing &lt;a href="https://ohmyz.sh/" target="_blank">ohmyzsh.sh&lt;/a>, and generally futzing. The main learning here was that installing things on OSX means using &lt;code>brew&lt;/code> a lot (e.g. &lt;code>brew install whatever&lt;/code>), while the Raspberry Pi OS - given it&amp;rsquo;s a type of &lt;a href="https://en.wikipedia.org/wiki/Debian" target="_blank">Debian&lt;/a> system, like &lt;a href="https://en.wikipedia.org/wiki/Ubuntu" target="_blank">Ubuntu&lt;/a> (the most popular (?) Linux OS) - used a lot of &lt;code>sudo apt get install&lt;/code>. Other than that, this part was basically smooth sailing and not much to report.&lt;/p>
&lt;p>Third was getting acquainted with the actual software for the Enviro. I relied heavily on &lt;a href="https://learn.pimoroni.com/tutorial/sandyj/getting-started-with-enviro-plus" target="_blank">this tutorial from the creators, &lt;em>Getting Started with Enviro+&lt;/em>&lt;/a>, not to be confused with &lt;a href="https://learn.pimoroni.com/tutorial/sandyj/getting-started-with-enviro-phat" target="_blank">&lt;em>this&lt;/em> very similarly titled tutorial for their older model&lt;/a>. HEHHHH. Yeah, I definitely got confused. And that&amp;rsquo;s the main thing I learned in this Pi project - that these projects are small and often changing and so it takes a bit of detective work to figure out how all the pieces go together. Which was fun! Very gratifying!&lt;/p>
&lt;p>Anyway, the pieces I ended up needing were the &lt;a href="https://github.com/pimoroni/enviroplus-python" target="_blank">&lt;code>enviroplus-python&lt;/code> library&lt;/a> (Pimoroni has, again, a &lt;em>very similar&lt;/em> one, &lt;code>enviro-phat&lt;/code>, which I won&amp;rsquo;t link because then you will get confused. I&amp;rsquo;m pretty sure &lt;code>enviroplus-python&lt;/code> is the one we should be using, at least at this point in time.)&lt;/p>
&lt;h2 class="relative group">More hardware
&lt;div id="more-hardware" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#more-hardware" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>So this library was super interesting. It basically installed a bunch of &lt;em>other&lt;/em> Pimoroni Python packages which related to the sensors on the pHat (pHAT? HAT? &lt;a href="https://www.sparkfun.com/pHATs" target="_blank">read more here&amp;hellip;&lt;/a>). These sensors are, specifically:&lt;/p>
&lt;ul>
&lt;li>A BME280 sensor which records temperature, humidity, and pressure. I believe the official docs are &lt;a href="https://www.bosch-sensortec.com/media/boschsensortec/downloads/product_flyer/bst-bme280-fl000.pdf" target="_blank">here&lt;/a>.&lt;/li>
&lt;li>An LTR-559 light and (optical) proximity sensor. I believe the official docs for &lt;em>that&lt;/em> are &lt;a href="https://optoelectronics.liteon.com/upload/download/DS86-2013-0003/LTR-559ALS-01_DS_V1.pdf" target="_blank">these&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>There&amp;rsquo;s also a tiny microphone and LED screen, though I haven&amp;rsquo;t explored those almost at all yet. More to come on those!&lt;/p>
&lt;h2 class="relative group">And more software
&lt;div id="and-more-software" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#and-more-software" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The main questions I had, after running through the &lt;code>enviroplus-python&lt;/code> off-the-shelf examples, was &lt;em>what were the units on these sensors?&lt;/em> The proximity sensoring, especially, was kinda baffling. The numbers get very &amp;ldquo;big&amp;rdquo; (in the thousands) if you put your hand over the sensor, and quite low (down to zero) if you don&amp;rsquo;t. So, thousands of&amp;hellip; what?&lt;/p>
&lt;p>It turned out finding the answer to this question was not straightforward, and the official answer was basically an &amp;ldquo;uhhhh 🤷&amp;rdquo;. &lt;a href="https://github.com/pimoroni/ltr559-python/issues/3" target="_blank">This GitHub issue includes the Pimoroni thoughts on the matter&lt;/a> and &lt;a href="https://optoelectronics.liteon.com/upload/download/DS86-2013-0003/LTR-559ALS-01_DS_V1.pdf" target="_blank">the official docs&lt;/a> basically say it&amp;rsquo;s &amp;ldquo;count&amp;rdquo;. Though count of what?!&lt;/p>
&lt;blockquote>
&lt;h4 class="relative group">A brief digression on how the optical sensor works
&lt;div id="a-brief-digression-on-how-the-optical-sensor-works" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#a-brief-digression-on-how-the-optical-sensor-works" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;/blockquote>
&lt;blockquote>
&lt;p>I dove into this a little bit. The LTR-559 is an &lt;strong>optical&lt;/strong> sensor. (There are other types of &lt;a href="https://en.wikipedia.org/wiki/Proximity_sensor" target="_blank">proximity sensors&lt;/a> that use other parts of the electromagnetic spectrum to &amp;ldquo;see&amp;rdquo; if there&amp;rsquo;s an object in front of them.) An optical sensor works by using light - it measures the reflected light, as far as I can tell. So the numbers the sensor is returning are a &amp;ldquo;count&amp;rdquo; (according to the official docs), which the Pimoroni authors &lt;a href="https://github.com/pimoroni/ltr559-python/issues/3" target="_blank">think&lt;/a> is either the number of LED pulses the sensor emitted that returned an object (e.g. &amp;ldquo;I shot out 500 pulses and 499 of them reflected light back, so your number is 499&amp;rdquo;?) or the actual &amp;ldquo;number of light units&amp;rdquo;, typically measured as a &lt;code>lux&lt;/code> (&lt;a href="https://en.wikipedia.org/wiki/Lux" target="_blank">wiki&lt;/a> - a measure of &amp;ldquo;luminous flux per unit area&amp;rdquo;).&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Either way, big numbers from that sensor = lots of reflected light = something is close.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;a href="https://www.youtube.com/watch?v=QfQ_bL8AeGo" target="_blank">This YouTube video by Modern Robotics Inc&lt;/a> gives a very nice and thorough (and digestible) explanation.&lt;/p>
&lt;/blockquote>
&lt;h2 class="relative group">Final Software: the actual little script
&lt;div id="final-software-the-actual-little-script" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#final-software-the-actual-little-script" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>To start with, I just wanted to start collecting the data for some of our rooms. For now, I&amp;rsquo;m just writing that data to a CSV file that the Pi is holding, and every so often I &lt;code>ssh&lt;/code> into the Pi and check on it. I&amp;rsquo;ve been noodling over the idea of (1) making the data more stream-y (&lt;a href="http://kafka.apache.org/" target="_blank">Kafka?&lt;/a>) and/or (2) making a web UI (like the &lt;a href="http://angelaambroz.com/blog/posts/2021/Feb/28/setting_up_the_pihole_finally/" target="_blank">Pi-hole&lt;/a>!) using &lt;a href="https://flask.palletsprojects.com/en/1.1.x/" target="_blank">Flask&lt;/a> and &lt;a href="https://bokeh.org/" target="_blank">Bokeh&lt;/a> (Bokeh so pretty&amp;hellip;).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="ch">#!/usr/bin/env python3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">csv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">ltr559&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">LTR559&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">bme280&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BME280&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ltr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LTR559&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">bme&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BME280&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">header&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;datetime&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;light&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;proximity&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;temperature&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;humidity&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">data_file&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;data/room.csv&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Write the header once&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data_file&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;w&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">writer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">csv&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">writer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">writer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">writerow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">header&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data_file&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">writer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">csv&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">writer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">today&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1"> %H:%M:%S&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ltr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">update_sensor&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lux&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ltr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_lux&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ltr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_proximity&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">temp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">bme&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_temperature&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pres&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">bme&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_pressure&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">hum&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">bme&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_humidity&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">writer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">writerow&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">today&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">lux&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">prox&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">temp&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">hum&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">except&lt;/span> &lt;span class="ne">KeyboardInterrupt&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The units for the other sensor readings (apart from proximity) are:&lt;/p>
&lt;ul>
&lt;li>LTR559 - Light: &lt;a href="https://en.wikipedia.org/wiki/Lux" target="_blank">lux&lt;/a>&lt;/li>
&lt;li>BME280 - Temperature: Celsius&lt;/li>
&lt;li>BME280 - Pressure: &lt;a href="https://en.wikipedia.org/wiki/Pascal_%28unit%29" target="_blank">hectopascal&lt;/a> (hPa)&lt;/li>
&lt;li>BME280 - Humidity: &lt;a href="https://en.wikipedia.org/wiki/Humidity" target="_blank">relative humidity&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Interpreting the results
&lt;div id="interpreting-the-results" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#interpreting-the-results" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>My brain is in Fahrenheit, but I have a general sense of Celsius (20 is comfortable! 0 is freezing! 40 is hotttt). I have no similar sense for luxes, hectopascals, and even relative humidity. The relative humidity in the rooms we measured has always been around ~17%. Which seems awfully low. But what does that mean? Apparently the &lt;a href="https://www.coolray.com/help-guides/indoor_comfort_issues_to_much_or_too_little_humidity" target="_blank">Sahara Desert is typically around 25%&lt;/a>. What the heck.&lt;/p>
&lt;p>Oh yeah, and I need to compensate for the heat of the Raspberry Pi, as &lt;a href="https://github.com/pimoroni/enviroplus-python/blob/master/examples/compensated-temperature.py" target="_blank">this Pimoroni example shows&lt;/a>.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Conclusion
&lt;div id="conclusion" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Well, this was a lot of fun, despite what my &lt;a href="http://angelaambroz.com/blog/posts/2021/Feb/28/setting_up_the_pihole_finally/" target="_blank">initial Pi pessimism (&amp;ldquo;is it all just off the shelf?!&amp;rdquo;)&lt;/a>. I do feel like my creativity has been unlocked and I&amp;rsquo;m learning lots of little things as well (hectopascals!); those were the two things I was after (learning, creativity). I&amp;rsquo;m very pumped to keep tinkering with this and to BUY MORE PIIIIIIS.&lt;/p></description></item><item><title>Setting up the Pi-hole (finally!)</title><link>https://www.angelaambroz.com/posts/setting_up_the_pihole_finally/</link><pubDate>Sun, 28 Feb 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/setting_up_the_pihole_finally/</guid><description>
&lt;h2 class="relative group">Finally getting my Pi-hole act together
&lt;div id="finally-getting-my-pi-hole-act-together" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#finally-getting-my-pi-hole-act-together" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I have been meaning to do something with the multiple (!) Raspberry Pis I&amp;rsquo;ve received over the years, and never got around to it. Until this weekend! Let us take a journey through the Pi-hole project.&lt;/p>
&lt;h2 class="relative group">The Raspberry Pi
&lt;div id="the-raspberry-pi" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-raspberry-pi" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Raspberry_Pi_4_Model_B_-_Side.jpg/640px-Raspberry_Pi_4_Model_B_-_Side.jpg" alt="the pi" />
&lt;/figure>
&lt;/p>
&lt;p>Chances are if you&amp;rsquo;re reading this blog, you know what a &lt;a href="https://en.wikipedia.org/wiki/Raspberry_Pi" target="_blank">Raspberry Pi&lt;/a> is. But perhaps you don&amp;rsquo;t! In which case: it is a small, cheap ($30) barebones computer used by hobbyists for numerous silly ideas. You can plug in the various accessories - monitor, keyboard, mouse - load an operating system, and you have a computer. You can &lt;em>also&lt;/em> plug in various sensors, cameras, microphones, and such, and create a wide array of random widgets and doo-dads: robots with computer vision and so on. There are many, many books about this.&lt;/p>
&lt;h2 class="relative group">The Pi-hole
&lt;div id="the-pi-hole" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-pi-hole" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>One popular project is setting up a Raspberry Pi as a network-wide ad blocker. The &lt;a href="https://pi-hole.net/" target="_blank">Pi-hole project&lt;/a> makes this very, very easy and friendly. The basic idea is: you route all Internet traffic on your local network through your Raspberry Pi. The Pi-hole software parses a giant blocklist (as well as an optional whitelist) of domains. If the Internet request contains one of those persona non grata domains, it &lt;a href="https://en.wikipedia.org/wiki/DNS_sinkhole" target="_blank">returns a false result - sending it to a DNS sinkhole&lt;/a>. In this way, you:&lt;/p>
&lt;ul>
&lt;li>Spare a lot of your bandwidth from awful, pervasive ad traffic.&lt;/li>
&lt;li>For all the devices on your network (computers, phones, TVs, game consoles).&lt;/li>
&lt;li>And it provides a &lt;a href="https://i2.wp.com/pi-hole.net/wp-content/uploads/2018/04/Screenshot-2018-04-01-14.39.10.png" target="_blank">spiffy web UI&lt;/a> for you to monitor (a) who&amp;rsquo;s browsing what, (b) what&amp;rsquo;s getting blocked and let through, and (c) it lets you configure - to a very granular level - which domains are allowed and which aren&amp;rsquo;t.&lt;/li>
&lt;/ul>
&lt;p>I have been &lt;em>very, very tempted&lt;/em> to use a Pi-hole to sinkhole all social media domains. The Great Firewall of my house!! This has been vetoed, so far, by the other Internet users in my house.&lt;/p>
&lt;h2 class="relative group">Why not just use an ad-blocker
&lt;div id="why-not-just-use-an-ad-blocker" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#why-not-just-use-an-ad-blocker" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Since this was the main question I was asked by my other network users. The main reason is: an ad-blocker is device-based. Not even, it&amp;rsquo;s &lt;em>browser&lt;/em>-based. So you have to keep installing it on every new browser, on every new device. Pi-hole solves the problem once and for all.&lt;/p>
&lt;h2 class="relative group">How I set it up
&lt;div id="how-i-set-it-up" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-i-set-it-up" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;strong>Networking&lt;/strong> is one of those things I really, &lt;em>really&lt;/em> need to learn more about (&lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/20/i_heart_waves/" target="_blank">like Bluetooth!&lt;/a>), because otherwise - I swear - my ISP tries to scare me into renting their router or stuff like that. Anyway, so my &lt;strong>super basic&lt;/strong> understanding is that, after setting up your Pi on your network (I wired it via ethernet), you assign it a static IP address and then redirect all traffic to that IP address. Specifically, I followed this tutorial: &lt;a href="https://www.youtube.com/watch?v=4X6KYN1cQ1Y" target="_blank">Quick and Easy Pi-hole Setup 2021&lt;/a>.&lt;/p>
&lt;h2 class="relative group">More Pi-thoughts
&lt;div id="more-pi-thoughts" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#more-pi-thoughts" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>If you visit websites like &lt;a href="https://www.adafruit.com/" target="_blank">Adafruit&lt;/a> and &lt;a href="https://shop.pimoroni.com/" target="_blank">Pimoroni&lt;/a>, you&amp;rsquo;ll see lots of fun, inspiring projects. I used to be very intimidated by this stuff, because I couldn&amp;rsquo;t understand how it all came together. The hardware learning curve was (and mostly is) very steep for me, and seemed daunting. Hence why it took me three years to finally getting around to this. Now that I&amp;rsquo;ve finally broken that first barrier - turning on the Pi, connecting to it headlessly, and making it my home&amp;rsquo;s Pi-hole - I have the feeling of: &amp;ldquo;wait, is it always just off-the-shelf stuff?&amp;rdquo;&lt;/p>
&lt;p>Example: the &lt;a href="https://learn.pimoroni.com/tutorial/sandyj/getting-started-with-enviro-phat" target="_blank">Pimoroni Enviro pHAT&lt;/a>, which is a little board that comes with a bunch of weather-related sensors (humidity, temperature, light, noise). You can connect it to your Pi and monitor your indoor ambience. But, reading through the tutorial, it seems to be basically (a) solder this all together, (b) &lt;code>curl&lt;/code> the project and &lt;code>bash&lt;/code> install it, and (c) voila all your sensors now do stuff! It feels like cheating. It feels so off-the-shelf! Is the only creative contribution I make the way I present the sensor data? That&amp;rsquo;s boring.&lt;/p>
&lt;p>Anyway, so my Pi feelings are still in flux. I&amp;rsquo;m excited by the idea of DOING and MAKING and LEARNING stuff (my favorite things ever, after all). But I&amp;rsquo;m still scrambling a little at the base of this hardware maker mountain, trying to find projects that are both challenging but achievable (just like when I was trying to learn Python! ah, Zen mind, beginner&amp;rsquo;s mind).&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Some further reading and resources
&lt;div id="some-further-reading-and-resources" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#some-further-reading-and-resources" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://vicki.substack.com/p/ad-block-and-you-dont-stop" target="_blank">&amp;ldquo;Ad block and you don&amp;rsquo;t stop&amp;rdquo;, Normcore Tech&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://mitpress.mit.edu/books/spam" target="_blank">&amp;ldquo;Spam&amp;rdquo;, Finn Brunton&lt;/a>. One of my favorite books of 2014!&lt;/li>
&lt;li>&lt;a href="https://www.raspberrypi.org/" target="_blank">The Raspberry Pi Foundation&lt;/a>. They&amp;rsquo;re British!&lt;/li>
&lt;li>&lt;a href="https://www.lynda.com/Raspberry-Pi-training-tutorials/1693-0.html" target="_blank">Raspberry Pi Weekly, on Lynda&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Carrie Nation triptych</title><link>https://www.angelaambroz.com/posts/carrie_nation_triptych/</link><pubDate>Thu, 04 Feb 2021 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/carrie_nation_triptych/</guid><description>&lt;p>Made this for an art class I&amp;rsquo;m taking. It&amp;rsquo;s a three-panel exploration of what motivates my character, Carrie Nation (based on &lt;a href="https://en.wikipedia.org/wiki/Carrie_Nation" target="_blank">the historical Carrie Nation&lt;/a>, but with some important liberties taken). It relates specifically to plot points from my sci-fi short story, &lt;a href="http://www.beneath-ceaseless-skies.com/stories/the-good-deaths-part-ii/" target="_blank">The Good Deaths, Part II&lt;/a>.&lt;/p></description></item><item><title>Best books of 2020</title><link>https://www.angelaambroz.com/posts/best_books_of_2020/</link><pubDate>Thu, 17 Dec 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/best_books_of_2020/</guid><description>
&lt;h1 class="relative group">Overall stats
&lt;div id="overall-stats" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#overall-stats" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>This year, I read &lt;a href="https://www.goodreads.com/user_challenges/20858035" target="_blank">84 books&lt;/a>. The vast majority of these were picture books: either graphic novels or children&amp;rsquo;s books. At a glance, 29 (35%) were by POC, and 37 (44%) were by women. (This was just me guessing based on the author names and pictures, so it might be a little wrong.) So, no improvement &lt;a href="http://angelaambroz.com/blog/posts/2018/Dec/31/best_books_of_2018/" target="_blank">from 2018&lt;/a> on POC (2018: 33%), and a very decent improvement on reading women authors (2018: 21%). I noticed that &lt;em>many&lt;/em> of the children&amp;rsquo;s book authors were women, and many of the comix as well.&lt;/p>
&lt;p>Going forward, I&amp;rsquo;d like to:&lt;/p>
&lt;ul>
&lt;li>Again, re-commit myself to reading more by &lt;strong>&amp;ldquo;minority&amp;rdquo; authors&lt;/strong> (that term feels outdated?).&lt;/li>
&lt;li>I&amp;rsquo;m really enjoying &lt;strong>historical fiction&lt;/strong>, so more of that.&lt;/li>
&lt;li>I have read zero &lt;strong>poetry&lt;/strong> in forever; something to explore.&lt;/li>
&lt;li>More &lt;strong>STEM&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;p>Now to the awards!&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Most influential: &lt;a href="https://www.goodreads.com/book/show/52766871-usual-cruelty" target="_blank">Usual Cruelty&lt;/a>
&lt;div id="most-influential-usual-crueltyhttpswwwgoodreadscombookshow52766871-usual-cruelty" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#most-influential-usual-crueltyhttpswwwgoodreadscombookshow52766871-usual-cruelty" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Alec Karakatsanis&amp;rsquo;s &lt;a href="https://www.goodreads.com/book/show/52766871-usual-cruelty" target="_blank">Usual Cruelty&lt;/a>, about the criminal &amp;ldquo;injustice&amp;rdquo; system, was incredibly enlightening and informative. It blew my mind. I gifted it to several folks for the holidays.&lt;/p>
&lt;h2 class="relative group">Most pleasurable in the moment: &lt;a href="https://www.goodreads.com/book/show/2666.The_Bonfire_of_the_Vanities" target="_blank">Bonfire of the Vanities&lt;/a>
&lt;div id="most-pleasurable-in-the-moment-bonfire-of-the-vanitieshttpswwwgoodreadscombookshow2666the_bonfire_of_the_vanities" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#most-pleasurable-in-the-moment-bonfire-of-the-vanitieshttpswwwgoodreadscombookshow2666the_bonfire_of_the_vanities" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>More criminal justice things: &lt;a href="https://www.goodreads.com/book/show/2666.The_Bonfire_of_the_Vanities" target="_blank">Bonfire of the Vanities&lt;/a>, that peak of 80s excess. A blazing satire. So much cackling. We watched the movie in our book club as well and it was &lt;em>truly awful&lt;/em>. Amazingly bad. Bad as a film. Awful as a (re?)interpretation of a good book.&lt;/p>
&lt;p>Honorable mention to &lt;a href="https://www.goodreads.com/book/show/34051011-pachinko" target="_blank">Pachinko&lt;/a> as well.&lt;/p>
&lt;h2 class="relative group">Best comix: &lt;a href="https://www.goodreads.com/book/show/36700347-good-talk" target="_blank">Good Talk&lt;/a>
&lt;div id="best-comix-good-talkhttpswwwgoodreadscombookshow36700347-good-talk" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#best-comix-good-talkhttpswwwgoodreadscombookshow36700347-good-talk" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://www.goodreads.com/book/show/36700347-good-talk" target="_blank">Good Talk&lt;/a> by Mira Jacob was innovative aesthetically, with an authentic and poignant story of growing up the daughter of Indian immigrants.&lt;/p>
&lt;h2 class="relative group">Best kids&amp;rsquo; book: TIE! &lt;a href="https://www.goodreads.com/book/show/414149.Sheep_Out_to_Eat" target="_blank">Sheep Out to Eat&lt;/a> and &lt;a href="https://www.goodreads.com/book/show/24688.Cars_and_Trucks_and_Things_That_Go" target="_blank">Cars and Trucks and Things That Go&lt;/a>
&lt;div id="best-kids-book-tie-sheep-out-to-eathttpswwwgoodreadscombookshow414149sheep_out_to_eat-and-cars-and-trucks-and-things-that-gohttpswwwgoodreadscombookshow24688cars_and_trucks_and_things_that_go" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#best-kids-book-tie-sheep-out-to-eathttpswwwgoodreadscombookshow414149sheep_out_to_eat-and-cars-and-trucks-and-things-that-gohttpswwwgoodreadscombookshow24688cars_and_trucks_and_things_that_go" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Oh, this one is hard. But it must be a tie between &lt;a href="https://www.goodreads.com/book/show/414149.Sheep_Out_to_Eat" target="_blank">Sheep Out to Eat&lt;/a> and &lt;a href="https://www.goodreads.com/book/show/24688.Cars_and_Trucks_and_Things_That_Go" target="_blank">Cars and Trucks and Things That Go&lt;/a>. The sheep are delightful for their art, their knitting, and the rhythm and rhyme of their disasters. Boy, do they get up to some hijinx. The things that go are delightful for the absolute busy-ness, the chaos (a pickle truck!), the celebration of going for a ride (in &lt;em>something&lt;/em>), and for &lt;a href="https://www.goodreads.com/review/show/8891205?book_show_action=true&amp;amp;from_review_page=1" target="_blank">this review&lt;/a>.&lt;/p>
&lt;hr>
&lt;iframe src="https://giphy.com/embed/MUeQeEQaDCjE4" width="480" height="264" frameBorder="0" class="giphy-embed" allowFullScreen>&lt;/iframe>&lt;p>&lt;a href="https://giphy.com/gifs/waynes-world-wayne-campbell-MUeQeEQaDCjE4">via GIPHY&lt;/a>&lt;/p>
&lt;h1 class="relative group">Library Extension developers: Thank you!
&lt;div id="library-extension-developers-thank-you" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#library-extension-developers-thank-you" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>This year I re-discovered the library, namely that they have physical books. I talk about the glories of the library in my &lt;a href="http://angelaambroz.com/blog/posts/2020/Oct/22/breaking_up_with_big_tech_amzn/" target="_blank">anti-Amazon post&lt;/a>. But, srsly, &lt;a href="https://www.libraryextension.com/" target="_blank">Library Extension&lt;/a> has changed my life.&lt;/p></description></item><item><title>The post-pandemic world</title><link>https://www.angelaambroz.com/posts/the_postpandemic_world/</link><pubDate>Thu, 17 Dec 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/the_postpandemic_world/</guid><description>&lt;p>People are getting vaccinated. The end feels near and tangible!&lt;/p>
&lt;h2 class="relative group">Things I&amp;rsquo;m looking forward to in a post-pandemic world
&lt;div id="things-im-looking-forward-to-in-a-post-pandemic-world" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#things-im-looking-forward-to-in-a-post-pandemic-world" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Wearing a mask on my commute (I don&amp;rsquo;t know why)&lt;/li>
&lt;li>Cafe chatter and bustle&lt;/li>
&lt;li>Movie theaters&lt;/li>
&lt;li>Art museums!!!!&lt;/li>
&lt;li>Running without a mask on&lt;/li>
&lt;li>Curbside pickup continuing? Maybe?&lt;/li>
&lt;li>Natural history museum!&lt;/li>
&lt;li>Indoor gyms and play areas, etc&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Things I&amp;rsquo;m not looking forward to
&lt;div id="things-im-not-looking-forward-to" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#things-im-not-looking-forward-to" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Travel&lt;/li>
&lt;li>Commuting&lt;/li>
&lt;li>Crowds&lt;/li>
&lt;li>Reverse culture shock of &amp;ldquo;returning to normality&amp;rdquo;&lt;/li>
&lt;/ul></description></item><item><title>Play-Doh self-portrait</title><link>https://www.angelaambroz.com/posts/playdoh_selfportrait/</link><pubDate>Wed, 09 Dec 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/playdoh_selfportrait/</guid><description>&lt;p>Made some silly, amusing art. Self-portrait in acrylic yarn, Play-Doh, and a jumbo marker. Claymation is harder than it looks!&lt;/p></description></item><item><title>The Hard Tomorrow (2019) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/the_hard_tomorrow/</link><pubDate>Fri, 04 Dec 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/the_hard_tomorrow/</guid><description>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Eleanor Davis&lt;/li>
&lt;li>Number of pages: 152&lt;/li>
&lt;li>Year published: 2019&lt;/li>
&lt;li>Year read: 2020&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I read this through once, thinking it took place now. One plot point felt outlandish to me and then, reading other Goodreads reviews, I realized this is meant to take place in the very-near future: a sort of &amp;ldquo;one minute forward&amp;rdquo;, bleak Black Mirror-ish speculation. That fit the puzzle pieces together (specifically, that plot point I couldn&amp;rsquo;t quite believe), but what&amp;rsquo;s interesting is how I firmly believed every single other part of this - and just assumed it was a slice of life tale about being a 30something in this problematic landscape. &lt;br/>&lt;br/>Really well-observed; beautiful structured. The art is amazing. The pacing and execution are really impeccable. I&amp;rsquo;m so impressed. Can&amp;rsquo;t wait to read more from Eleanor Davis.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/43317538" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Vim!</title><link>https://www.angelaambroz.com/posts/vim/</link><pubDate>Thu, 03 Dec 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/vim/</guid><description>&lt;p>&lt;span class="caption">&lt;a href="https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two" target="_blank">seven, +/- two&lt;/a>&lt;/span>&lt;/p>
&lt;h1 class="relative group">Hello, world! :wq
&lt;div id="hello-world-wq" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#hello-world-wq" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>This is coming to you &lt;em>live&lt;/em> from a Vim terminal! Or is it a buffer? An insert mode thingie? Well, whatever it is, I am writing this in Vim.&lt;/p>
&lt;p>Long have I sought to vanquish the infamous learning curve. Many a time have I tumbled back to the bottom, into the warm embrace of PyCharm, Sublime, Atom, &lt;em>literally anything else&lt;/em> (except Emacs). Well, this year is the year. I am now halfway up (maybe?) the learning curve and enjoying it. I hereby proclaim I am &lt;strong>not going back&lt;/strong>. No! Never! I have &lt;a href="https://github.com/angelaambroz/.dotfiles/blob/master/system/.vimrc" target="_blank">dotfiles to prove it!&lt;/a>&lt;/p>
&lt;h2 class="relative group">What Vim?
&lt;div id="what-vim" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#what-vim" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I assume most people have a similarly horrible first impression with Vim. You get dropped into Vim sometimes, on servers and iirc on unconfigured git diffs, and then you flail around there, not understanding how to exit or scroll or where you even are (&amp;ldquo;Is this an editor? &lt;em>What is this?&lt;/em>&amp;rdquo;). In other words, it is an unfriendly text editor (built into your shell? I think?).&lt;/p>
&lt;h2 class="relative group">Why Vim?
&lt;div id="why-vim" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#why-vim" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>But, beyond supreme nerd cred (always a worthy goal in and of itself), why Vim? Here were my reasons:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Lightweight&lt;/strong>. Until now, I was using &lt;a href="https://www.jetbrains.com/pycharm/" target="_blank">PyCharm&lt;/a> for most of my development. It has pros and cons. Several pros: multiple cursors, jumping to definitions and usages of any function or variable, lots of gentle UX nudges of how bad your code is (e.g. grayed-out unused objects, auto-linting), and so on. It had three notable cons: it&amp;rsquo;s not free, it takes forever to load, and - &lt;em>most importantly&lt;/em> - configuring it was &lt;em>not&lt;/em> only a dotfile away.&lt;/li>
&lt;li>&lt;strong>Dotfile-able&lt;/strong>. Readers will remember &lt;a href="http://angelaambroz.com/blog/posts/2018/May/23/yet_another_dotfiles_repo/" target="_blank">I love dotfiles&lt;/a>, and, indeed, most of them withstood the ultimate test: getting a new machine set up. My Macbook was basically dead (btw Macbooks die so early these days wtf), and I needed to quickly spin up a new one. And I did! It didn&amp;rsquo;t take long! Except, oddly and ominously, on PyCharm, which suddenly had a super weird keymap - rendering all my typing so painful, like trying to write with my non-dominant hand. No, no nooo.&lt;/li>
&lt;li>&lt;strong>Programmatical&lt;/strong>. I have been quite swayed by the promises of Vim letting you type &amp;ldquo;as fast as you think&amp;rdquo;. Thought and words/code! As one! United! Very exciting. Also, &lt;a href="https://thoughtbot.com/blog/the-vim-learning-curve-is-a-myth" target="_blank">this blog post by thoughtbot&lt;/a> really convinced me to take the plunge - tldr: they claim it&amp;rsquo;ll only be a week before you&amp;rsquo;re &amp;ldquo;as fast as before&amp;rdquo;, and that, thus, everything after the first week is just gains.&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">A few of my favorite Vim things, so far
&lt;div id="a-few-of-my-favorite-vim-things-so-far" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#a-few-of-my-favorite-vim-things-so-far" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Well, it&amp;rsquo;s been less than a week, but I do feel like I&amp;rsquo;m now about as productive as I was before (!!!). Which is already amazing. Also, Vim has been impressing me with lots of little wing-dings and doo-dads. Yes, I am still annoyed I can&amp;rsquo;t just mouse and scroll IN THE USUAL FASHION, as I have for lo these many many computing years, but maybe the programmaticalness will win me over completely?&lt;/p>
&lt;p>Here are some nice things I&amp;rsquo;ve enjoyed so far:&lt;/p>
&lt;ul>
&lt;li>I love being able to run any shell command from Vim, e.g., I could run &lt;code>!make html &amp;amp;&amp;amp; make serve&lt;/code> right now and I would see my blog on a local server, &lt;em>and I wouldn&amp;rsquo;t have to leave Vim&lt;/em>. There. I just did it.&lt;/li>
&lt;li>To make up for the lack of mouse, there are a great many ways to search and find things, with (seemingly) any and all levels of precison. If you know the line number, it&amp;rsquo;s just &lt;code>:[line number]&lt;/code>. If you know the word, it&amp;rsquo;s just &lt;code>/[word]&lt;/code>. If you know it&amp;rsquo;s somewhere down there in the code, you can try &lt;code>shift+}&lt;/code> or &lt;code>ctrl+F&lt;/code> or &lt;code>shift+G&lt;/code>. Many options!&lt;/li>
&lt;li>&lt;strong>&lt;code>yank&lt;/code> and &lt;code>put&lt;/code>&lt;/strong>. I have been yanking (copying) and putting multiple lines, and it&amp;rsquo;s so easy: &lt;code>:[starting line number],[ending line number]y&lt;/code> and &lt;code>:[line to move it to]pu&lt;/code>.&lt;/li>
&lt;li>&lt;a href="https://github.com/kien/ctrlp.vim" target="_blank">CtrlP&lt;/a>: aka, fuzzy search through files (like in &lt;a href="https://atom.io/" target="_blank">Atom&lt;/a>).&lt;/li>
&lt;li>&lt;code>&amp;lt;leader&amp;gt; + d&lt;/code> goto the definition (thanks to &lt;a href="https://github.com/davidhalter/jedi-vim" target="_blank">jedi-vim&lt;/a>).&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Resources
&lt;div id="resources" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#resources" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://thoughtbot.com/upcase/vim" target="_blank">&lt;em>Learn Vim&lt;/em> by thoughtbot/Upcase&lt;/a> - This has been extremely helpful, especially their Big Tip to have a &lt;a href="https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two" target="_blank">&amp;ldquo;magical number seven&amp;rdquo;&lt;/a> living document cheat sheet to keep learning. My tiny whiteboard is perfect for that!&lt;/li>
&lt;li>&lt;a href="http://vimcasts.org/" target="_blank">Vimcasts&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.openvim.com/" target="_blank">OpenVim&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://vim.fandom.com/wiki/Tutorial" target="_blank">The Vim wiki&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://vimawesome.com/" target="_blank">VimAwesome&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Why is it so hard to make it in America?</title><link>https://www.angelaambroz.com/posts/why_is_it_so_hard_to_make_it_in_america/</link><pubDate>Fri, 06 Nov 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/why_is_it_so_hard_to_make_it_in_america/</guid><description>&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/yBdTVmSVq14" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen>&lt;/iframe>
&lt;p>One of my favorite songs (and performances), ever, seems especially appropriate today/this week. Charles Bradley was such a phenom. He sadly passed away in 2017, so soon after starting to achieve the recognition his talent deserved.&lt;/p></description></item><item><title>Wizzywig- Portrait of a Serial Hacker (2012) - ⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/wizzywig_portrait_of_a_serial_hacker/</link><pubDate>Fri, 06 Nov 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/wizzywig_portrait_of_a_serial_hacker/</guid><description>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Ed Piskor&lt;/li>
&lt;li>Number of pages: 288&lt;/li>
&lt;li>Year published: 2012&lt;/li>
&lt;li>Year read: 2020&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>An interesting, troubling book about very early hacking and phreaking. &lt;br/>&lt;br/>I&amp;rsquo;m always interested in the hacking mindset - the protagonist, Kevin &amp;ldquo;Boingthump&amp;rdquo; Phenicle, is constantly trying to reverse engineer and find loopholes in the phone system and the Internet. He doesn&amp;rsquo;t have a clear goal beyond seeing what can be done. Along the way, he accomplishes amazing feats. In a way, it&amp;rsquo;s like pure creativity. He does it because he can, because he must. There&amp;rsquo;s a great moment when his friend, growing increasingly uncomfortable with the semi-legal nature of their activities, begs him to stop - Kevin/Boingthump replies that that&amp;rsquo;s like asking him to stop being him. To him, life is a puzzle. Our modern world is a puzzle. A game to be cracked. An ADDICTIVE game. &lt;br/>&lt;br/>The feds are portrayed in all their bumbling incompetence and cruelty, shrieking about &amp;ldquo;cybercrime&amp;rdquo; they don&amp;rsquo;t understand. I immediately thought of &lt;a href="https://en.wikipedia.org/wiki/Aaron_Swartz">Aaron Swartz&lt;/a>. &lt;br/>&lt;br/>I didn&amp;rsquo;t love the art - it was grotesque, vulgar, cynical. And I spent a lot of time wondering how much was true (Phenicle is a composite of several historical h4x0rs); it made me want to read a history to learn more.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/13644998" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Breaking up with big tech- $AMZN</title><link>https://www.angelaambroz.com/posts/breaking_up_with_big_tech_amzn/</link><pubDate>Thu, 22 Oct 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/breaking_up_with_big_tech_amzn/</guid><description>
&lt;h2 class="relative group">Scorecard
&lt;div id="scorecard" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#scorecard" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;input checked="" disabled="" type="checkbox"> Facebook: deleted 2014&lt;/li>
&lt;li>&lt;input checked="" disabled="" type="checkbox"> Twitter: deleted 2019&lt;/li>
&lt;li>[] Amazon: actively trying to extricate myself&lt;/li>
&lt;li>[] Google: dreaming of breaking up&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 class="relative group">Motivation
&lt;div id="motivation" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#motivation" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h3 class="relative group">Jeff Bezos has way too much money, and I am tired of giving it to him
&lt;div id="jeff-bezos-has-way-too-much-money-and-i-am-tired-of-giving-it-to-him" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#jeff-bezos-has-way-too-much-money-and-i-am-tired-of-giving-it-to-him" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Jeff Bezos has $200 billion. The human brain boggles at such a number, so here&amp;rsquo;s a &lt;a href="https://mkorostoff.github.io/1-pixel-wealth/" target="_blank">picture of it&lt;/a>.&lt;/p>
&lt;p>No one human being deserves this much money (I don&amp;rsquo;t care how fast your shipping is). It is just plain wrong. It is unhealthy to society. I&amp;rsquo;m also personally offended by what Bezos chooses to do with his money: a fat lot of nothing. A toy space company (Blue Origin). When Bill Gates and the Gates Foundation exist as counterfactuals, Bezos should really be ashamed. There&amp;rsquo;s no reason he could possibly need so much money and I am going to do my small part in not giving him any more of it.&lt;/p>
&lt;p>Also, the way Amazon is run: &lt;a href="https://www.pbs.org/wgbh/frontline/film/amazon-empire/" target="_blank">the way the warehouse workers are exploited&lt;/a>, &lt;a href="https://www.nytimes.com/2015/08/16/technology/inside-amazon-wrestling-big-ideas-in-a-bruising-workplace.html" target="_blank">the way its corporate workforce is exploited&lt;/a>. All while Bezos keeps getting richer? No, thank you.&lt;/p>
&lt;h3 class="relative group">Putting the brakes on consumerism
&lt;div id="putting-the-brakes-on-consumerism" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#putting-the-brakes-on-consumerism" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Amazon fought to patent the one-click buy button because, above all else, they want to make you CONSUME CONSUME CONSUME. This mindless consumerism is destroying the planet (all that cardboard!). I don&amp;rsquo;t need all this stuff.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">The anti-$AMZN lifestyle: How to do it
&lt;div id="the-anti-amzn-lifestyle-how-to-do-it" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-anti-amzn-lifestyle-how-to-do-it" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h3 class="relative group">Toilet paper, etc.
&lt;div id="toilet-paper-etc" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#toilet-paper-etc" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>For big box essentials, Target and Walmart have the same app game, the same super-fast delivery game, and the same prices. These three behemoths are fighting, and consumers are benefiting. Yay, markets? So for all those &amp;ldquo;oh shit, we&amp;rsquo;re out of TP&amp;rdquo; moments, it&amp;rsquo;s &lt;em>very&lt;/em> easy to switch. Bonus: Target and Walmart also exist in the real world, so you can physically go to the store if you really, really need that thing today. (It&amp;rsquo;s called 1-Day Shipping, only you drive. Bonus: no cardboard boxes!)&lt;/p>
&lt;h3 class="relative group">Books
&lt;div id="books" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#books" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;h4 class="relative group">Ebooks and audiobooks
&lt;div id="ebooks-and-audiobooks" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#ebooks-and-audiobooks" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>This is where you save a lot of money by not-Amazoning.&lt;/p>
&lt;p>If you&amp;rsquo;re in the US: first, get a library card at your local library. If you&amp;rsquo;re not in the US, you can probably &lt;a href="https://www.aworldadventurebybook.com/blog/libraries-with-non-resident-borrowing-privileges" target="_blank">still get a US library card for either free or a moderate yearly fee (e.g. $50/year for a New York Public Library card)&lt;/a>.&lt;/p>
&lt;p>Second, connect the &lt;a href="https://www.overdrive.com/apps/libby/" target="_blank">Libby app&lt;/a> to any and all libraries you can get a card with. This will be your library portal and your audiobook app.&lt;/p>
&lt;p>Third, get the &lt;a href="https://www.libraryextension.com/" target="_blank">Library Extension&lt;/a> browser extension. It&amp;rsquo;ll tell you when a book you&amp;rsquo;re looking at on Amazon or Goodreads is at your library.&lt;/p>
&lt;p>Fourth, you&amp;rsquo;ll notice that many popular ebooks and audiobooks are checked out. Put these on hold, until you&amp;rsquo;ve maxed out your holds on all your cards. &lt;em>Then&lt;/em>, and this is the 🔥pro tip🔥: &lt;strong>&amp;ldquo;pause&amp;rdquo; all your holds for the max length possible (6 months)&lt;/strong>. You&amp;rsquo;ll still move ahead in the line. Once you&amp;rsquo;re ready to actually borrow the audiobook/ebook, unpause your hold. You can probably find something to borrow while you wait for the really good stuff.&lt;/p>
&lt;p>If you simply &lt;em>must&lt;/em> pay for your audiobooks, &lt;a href="https://libro.fm/" target="_blank">Libro.fm&lt;/a> competes with Amazon on prices ($15/month memberships) and their credits roll over (unlike Audible&amp;rsquo;s).&lt;/p>
&lt;h4 class="relative group">Physical books
&lt;div id="physical-books" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#physical-books" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>This is where you might spend more or, if you&amp;rsquo;re creative, much less.&lt;/p>
&lt;p>I advocate buying used books when at all possible. For this, you can see if local used bookstores near you have an online presence. I have a local used bookstore with an incredible catalog and decent online presence. There are also some thrift marketplaces like &lt;a href="https://www.mercari.com/" target="_blank">Mercari&lt;/a> (for everything) or &lt;a href="https://www.biblio.com/" target="_blank">Biblio&lt;/a> (for books). If you live in a hippie area, you may also have a &lt;a href="https://littlefreelibrary.org/" target="_blank">Little Free Library&lt;/a> near you.&lt;/p>
&lt;p>If you want to buy a new book as a gift or splurge, then &lt;a href="https://bookshop.org/" target="_blank">Bookshop.org&lt;/a> is my go-to: you pay more than Amazon, but that money goes to a local independent bookseller of your choice.&lt;/p>
&lt;h4 class="relative group">Super rare physical books
&lt;div id="super-rare-physical-books" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#super-rare-physical-books" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>Sometimes there is a magical book that you simply must have and it looks like Amazon is the only place that has it. I recently ran into this with &lt;a href="https://www.amazon.com/Figuring-Fibers-Carolyn-Yackel/dp/1470429314" target="_blank">Figuring Fibers, by Carolyn Yackel and sarah-marie belcastro&lt;/a>. This is a pretty niche book (math + knitting!) and I didn&amp;rsquo;t see it in my usual places. I was about to resort to Amazon when, thanks to a little bit of Googling, I found that the &lt;a href="https://bookstore.ams.org/mbk-117/" target="_blank">American Mathematical Society was selling it&lt;/a> - and for cheaper than Amazon! I can report that the AMS also shipped it super duper fast.&lt;/p>
&lt;p>Basically, trying to avoid Amazon actually exposes you to this whole giant, thriving, diverse ecosystem of &lt;em>other&lt;/em> markets - which are often cooler, cheaper, and more interesting! Who knew the AMS sold books! And so on.&lt;/p>
&lt;h3 class="relative group">Prime Video
&lt;div id="prime-video" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#prime-video" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Again, there&amp;rsquo;s tons of movies to watch through your library (&lt;a href="https://www.kanopy.com/" target="_blank">Kanopy&lt;/a>) and via Google&amp;rsquo;s massive movie archive on YouTube.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">A great resource
&lt;div id="a-great-resource" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#a-great-resource" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://threshold.us/c/cancelprime/amazon-alternatives" target="_blank">Amazon alternatives&lt;/a>&lt;/strong> A great, curated list of alternatives. I used this as my main jumping off point.&lt;/li>
&lt;/ul></description></item><item><title>Automated collaboration</title><link>https://www.angelaambroz.com/posts/automated_collaboration/</link><pubDate>Wed, 21 Oct 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/automated_collaboration/</guid><description>&lt;p>Hi. Gee whiz, do I like &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration" target="_blank">continuous integration (CI)&lt;/a>. Though, hmm, that wiki entry has a very different definition from what I mean. I mean CI as in automated testing of your code upon merging into a GitHub or GitLab repo.&lt;/p>
&lt;p>Anyway, one of the coolest things I learned &lt;a href="http://angelaambroz.com/blog/posts/2020/Oct/16/the_lonely_3/" target="_blank">from working a little bit on open source&lt;/a> was how to run a super-tight ship. Given that these big projects like &lt;a href="https://github.com/pandas-dev/pandas" target="_blank">pandas&lt;/a> need to operate with a la carte contributions, a lot of the management of those contributions is automated: automatic testing, yes, but even fancier stuff, like automatic documentation, automatic coverage and super-opinionated formatting.&lt;/p>
&lt;p>I just integrated a few of these tools into my own work, and I wanted to talk about them.&lt;/p>
&lt;h2 class="relative group">Automatic test coverage with &lt;code>coverage&lt;/code>
&lt;div id="automatic-test-coverage-with-coverage" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#automatic-test-coverage-with-coverage" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://nedbatchelder.com/" target="_blank">Ned Batchelder&lt;/a> has a great PyCon talk on testing in general: &lt;a href="https://www.youtube.com/watch?v=FxSsnHeWQBY" target="_blank">Getting started with testing (PyCon 2014)&lt;/a>. My main takeaway from this talk was &lt;strong>respect the dignity of tests&lt;/strong> 🙇. They do not have to suck. They can be as beautiful and programmy as the rest of your code.&lt;/p>
&lt;p>But anyway, Ned also has a great package, &lt;a href="https://coverage.readthedocs.io/en/coverage-5.3/" target="_blank">&lt;code>coverage&lt;/code>&lt;/a>, which can integrate with tools like &lt;a href="https://docs.pytest.org/en/stable/" target="_blank">&lt;code>pytest&lt;/code>&lt;/a> (beloved &lt;code>pytest&lt;/code>) to tell you which functions - nay, even lines - of your code are missed by tests.&lt;/p>
&lt;p>I used &lt;code>coverage&lt;/code> recently to auto-fail any merge requests on a repo by putting this in my CI config file:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">coverage run -m --source&lt;span class="o">=&lt;/span>my_cool_code/ pytest
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">coverage report --fail-under &lt;span class="m">95&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This basically says: your code must have at least 95% test coverage to pass CI. I like this because I often add new features and then de-prioritize the tests for them - thinking, well, I&amp;rsquo;ll get to those eventually. No longer!&lt;/p>
&lt;h2 class="relative group">Automatic docstring coverage with &lt;code>interrogate&lt;/code>
&lt;div id="automatic-docstring-coverage-with-interrogate" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#automatic-docstring-coverage-with-interrogate" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://www.roguelynn.com/" target="_blank">Lynn Root&lt;/a> has a super cool beta project called &lt;a href="https://interrogate.readthedocs.io/en/latest/" target="_blank">&lt;code>interrogate&lt;/code>&lt;/a> that basically does the same thing as &lt;code>coverage&lt;/code>, but for docstrings. Once again, you can easily integrate it into your CI with the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">interrogate --quiet --fail-under &lt;span class="m">95&lt;/span> my_cool_code/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>As above, I&amp;rsquo;m setting CI up to fail whenever docstring coverage falls under 95%. Yes, I&amp;rsquo;m strict! No more cryptic functions.&lt;/p>
&lt;h2 class="relative group">Automatic code formatting with &lt;code>black&lt;/code>
&lt;div id="automatic-code-formatting-with-black" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#automatic-code-formatting-with-black" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://github.com/psf/black" target="_blank">&lt;code>black&lt;/code>&lt;/a> is a quite opinionated formatter that will, if run on your code, automatically re-format it according to both the &lt;a href="https://www.python.org/dev/peps/pep-0008/" target="_blank">PEP8 standard&lt;/a>, as well as the opinions of its maintainers. It&amp;rsquo;s like me when someone asks me to read their email for the content, not copyediting. I CANNOT &lt;em>NOT&lt;/em> COPYEDIT, OKAY. That is how &lt;code>black&lt;/code> is.&lt;/p>
&lt;p>Anyway, given how it&amp;rsquo;s tightly coupled with - and seemingly blessed by - the &lt;a href="https://github.com/psf" target="_blank">Python Software Foundation&lt;/a>, I feel comfortable setting it as a CI requirement as well: all MRs must have &amp;ldquo;blackened&amp;rdquo; Python code to be accepted. One format = better readability. Hooray.&lt;/p>
&lt;p>This is the line in my CI config:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">black --check my_cool_code/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It&amp;rsquo;ll bounce back if any files fail &lt;em>not&lt;/em> to be modified by &lt;code>black&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">🎉 Summary 🎉
&lt;div id="-summary-" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#-summary-" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>All this to say: now MRs into my project will be more onerous, because my CI has become quite strict indeed. But the marginal added work when merging will, I hope, reap great rewards in the long run - clean, robust code that fails less often, and is easier to read and understand! 😭&lt;/p></description></item><item><title>The lonely 3%</title><link>https://www.angelaambroz.com/posts/the_lonely_3/</link><pubDate>Fri, 16 Oct 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/the_lonely_3/</guid><description>&lt;p>Hey, it&amp;rsquo;s October. Which means 2 things:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://hacktoberfest.digitalocean.com/" target="_blank">Hacktoberfest&lt;/a>! [make 4 open source contributions, win t-shirt]&lt;/li>
&lt;li>and &lt;a href="https://inktober.com/" target="_blank">Inktober&lt;/a>! [draw in ink every day, buy t-shirt?]&lt;/li>
&lt;/ol>
&lt;p>Let&amp;rsquo;s talk about open source.&lt;/p>
&lt;h2 class="relative group">Some context
&lt;div id="some-context" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#some-context" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;ve been revolutionizing my learning tools lately - discarding some (arrivederci, &lt;a href="http://angelaambroz.com/blog/tag/omscs.html" target="_blank">🐝&lt;/a>!), trying new ones - in an effort to get really super efficient in learning. I want to really maximize the value-add I get when I embark on new stuff now, since the intrinsic opportunity cost of my time is VERY high now. One of the big new ideas I had in terms of &amp;ldquo;how can I most efficiently get better and learn a lot?&amp;rdquo; was contributing to open source 🎉!&lt;/p>
&lt;p>At the moment, &lt;a href="https://www.wired.com/2017/06/diversity-open-source-even-worse-tech-overall/" target="_blank">3%&lt;/a> of open source contributions come from women. When women hide their genders while making GitHub pull requests (PRs), &lt;a href="https://peerj.com/articles/cs-111/" target="_blank">their code is more likely to be accepted than PRs made by men&lt;/a>. So that&amp;rsquo;s interesting.&lt;/p>
&lt;p>This makes the &lt;a href="https://computer.howstuffworks.com/internet/basics/where-are-women-of-wikipedia.htm" target="_blank">16%&lt;/a> proportion of Wiki contributors who are women seem, &lt;a href="https://www.youtube.com/watch?v=YBGrYxWbyhg" target="_blank">as Esther Duflo said in a similar comment about underrepresented groups in economics&lt;/a>, positively numerous&amp;hellip;&lt;/p>
&lt;h2 class="relative group">Contributing to open source: Pros
&lt;div id="contributing-to-open-source-pros" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#contributing-to-open-source-pros" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Learn from the big guns.&lt;/strong> Contributing to &lt;a href="https://github.com/pandas-dev/pandas" target="_blank">pandas&lt;/a>, &lt;a href="https://github.com/scikit-learn/scikit-learn" target="_blank">sklearn&lt;/a>, and others was like temporarily joining some high-powered teams of smart people. It was definitely intimidating, and honestly the culture shock and environment setup took a &lt;em>lot&lt;/em> of work in the beginning. But I learned so much about how projects can be set up, how Python can be written, and how teams can work efficiently.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Learning a la carte.&lt;/strong> The other nice thing about OS is that you can pick it up and put it down as and when you have time. My schedule is lumpy!&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Build a public-facing portfolio (aka transparency and prestige).&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>See and be seen.&lt;/strong> If you contribute a &lt;em>lot&lt;/em>, I presume you get more and more well-known with the core devs. So you&amp;rsquo;re basically networking.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 class="relative group">Contributing to open source: Cons
&lt;div id="contributing-to-open-source-cons" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#contributing-to-open-source-cons" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>I know you like to job, so I put job in your job so you could job while you job.&lt;/strong> As I said in the first pro, contributing to OS was like doing another job on top of my actual job. I was learning a lot, and the two jobs cross-pollinated for sure, but oof, I was pretty tired by the end.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Hostile work environment.&lt;/strong> OS has a bad rep - maybe one of the worst reps? - in tech for being unfriendly (&lt;a href="https://www.newyorker.com/science/elements/after-years-of-abusive-e-mails-the-creator-of-linux-steps-aside" target="_blank">to put it mildly&lt;/a>). This can really limit contributions - you want to join projects that have good cultures, and it&amp;rsquo;s hard to read culture from the outside looking in (though looking at discussions on old PRs can help). Thankfully, both &lt;code>pandas&lt;/code> and &lt;code>sklearn&lt;/code> were making clear efforts to be friendly - or, at least, friendly enough. Super efficient, but not mean.&lt;/p>
&lt;/li>
&lt;/ol></description></item><item><title>Greetings from the pandemic</title><link>https://www.angelaambroz.com/posts/greetings_from_the_pandemic/</link><pubDate>Mon, 28 Sep 2020 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/greetings_from_the_pandemic/</guid><description>
&lt;h2 class="relative group">May you live in interesting times / Willkommen in der Zukunft
&lt;div id="may-you-live-in-interesting-times--willkommen-in-der-zukunft" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#may-you-live-in-interesting-times--willkommen-in-der-zukunft" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://www.netflix.com/title/80100172" target="_blank">Dark&lt;/a> is a three-season German-language Netflix show that was produced and released between 2017 and 2020. It&amp;rsquo;s a sci-fi show that centralizes time travel, and all the various causal pickles you end up in when you could end up both Marty McFly senior &lt;em>and&lt;/em> junior. It&amp;rsquo;s a lot of fun. The casting of characters at different ages is, mwah, amazing. A delight.&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://media.giphy.com/media/d3ksbEi9mSqvAgYE/giphy.gif" alt="dark" />
&lt;/figure>
&lt;/p>
&lt;p>The show takes place in a bunch of different times. At one point in the show&amp;rsquo;s near future, a nuclear apocalypse happens. We spend a lot of plot time trying to avert this. Characterizations are defined by how they react to it. The show mostly asks: do we have free will? It mostly answers: not if we can&amp;rsquo;t change our desires. Blah blah.&lt;/p>
&lt;p>Anyway. The show was filmed pre-covid, and now we&amp;rsquo;re all living in this very weird covid reality. And the show is a pre-covid artifact about some imagined terrible dystopia. Hm.&lt;/p>
&lt;h2 class="relative group">Anyway, hello 👋
&lt;div id="anyway-hello-" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#anyway-hello-" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>So I really recommend Dark. It&amp;rsquo;s so fun. Maybe I&amp;rsquo;ll make a post about my Covid Lifestyle, and recommend all my other new hobbies.&lt;/p>
&lt;p>Either way, I found my SSH keys for this blog (only took me a year!) and so new content is forthcoming. 🎉&lt;/p>
&lt;h2 class="relative group">Credits
&lt;div id="credits" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#credits" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The GIF on this post&amp;rsquo;s summary is by &lt;a href="https://giphy.com/lukesistegia" target="_blank">Lukesistegià&lt;/a>:
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://media.giphy.com/media/WoXYS0FvVYiD8mULm5/giphy.gif" alt="gif art" />
&lt;/figure>
&lt;/p></description></item><item><title>Permanent Record (2019) - ⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/permanent_record/</link><pubDate>Fri, 18 Oct 2019 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/permanent_record/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/permanent_record/book_jacket_hu468366809dc44b113671840df92afe6e_57001_330x0_resize_q75_box.jpg 330w,
/posts/permanent_record/book_jacket_hu468366809dc44b113671840df92afe6e_57001_660x0_resize_q75_box.jpg 660w,
/posts/permanent_record/book_jacket_hu468366809dc44b113671840df92afe6e_57001_1024x0_resize_q75_box.jpg 1024w,
/posts/permanent_record/book_jacket_hu468366809dc44b113671840df92afe6e_57001_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/permanent_record/book_jacket_hu468366809dc44b113671840df92afe6e_57001_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Edward Snowden&lt;/li>
&lt;li>Number of pages: 339&lt;/li>
&lt;li>Year published: 2019&lt;/li>
&lt;li>Year read: 2019&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Wow. Very interesting. &lt;br/>&lt;br/>This was one of those (rare) books where I am just THIRSTING to read other people&amp;rsquo;s reviews - because I suspect my feelings are shared - but I kept myself from it, since I wanted to give an unvarnished reaction. &lt;br/>&lt;br/>So, I&amp;rsquo;d give Ed Snowden the whistleblower 5 stars for his clarity of thought, strength of principle, and courage. He did something very important for our civil liberties, and for any hope we might have of averting a real-life 1984 dystopia. He pulled back the curtain on the panopticon, and we should always be grateful for that.&lt;br/>&lt;br/>I&amp;rsquo;d also give the guts of his actual whistleblowing act - particularly since I remember watching it &amp;ldquo;live&amp;rdquo; in 2013 - 5 stars for sheer adrenaline. I remember when he made that Guardian video unmasking himself, and when he disappeared off the face of the planet: only to turn up stuck in Russia after a failed escape to Ecuador. High drama!&lt;br/>&lt;br/>I give his writing&amp;hellip; 3 stars?! Like it&amp;rsquo;s both unexpectedly good (whoa, he foreshadowed his own life story with a pop 1980s reference that ALSO contextualized his upbringing! bravo), unexpectedly cheesy (boy, can his prose get purple), and unexpectedly - and disappointingly - humble-braggy. I mean, this read like a Tom Clancy novel. It&amp;rsquo;s this very red-blooded, very American (&amp;lsquo;murca!), very 90s, rah rah justice story that seems - like Tom Clancy novels! - to feel so morally basic, so straightforward (and even thin characterizations!). I mean, fair. In a way, it WAS morally basic. The post-9/11 bulk collection/NSA panopticon IS a monster. It just takes guts to point it out, and woke-ness to notice/care. But Snowden paints himself as a hero so thoroughly, humble-brags &lt;em>so&lt;/em> much, that I found myself getting pretty annoyed. &lt;br/>&lt;br/>It&amp;rsquo;s actually interesting to compare his authorial voice against the voice of &lt;a href="https://www.goodreads.com/review/show/2384757761?book_show_action=false&amp;from_review_page=1">Aaron Swartz&lt;/a>, who held a lot of the same beliefs and was (I think?) a greater talent, but took a very different (and tragic) path. Aaron Swartz&amp;rsquo;s writings revealed a young man who really burned with an inner moral fire - he was almost like a prophet. It made his writings incredibly compelling to read, but also alienating. Snowden, on the other hand, sounds MUCH more down to Earth - but also kinda&amp;hellip; vain?! And, like, 90s basic technogeek (fetishizing Japanese culture, for example)? I feel strange criticizing his voice, but his extended digressions on his all-American, all-patriot pedigree jarred me; as did his heroic portrayal of how he really wanted to go to a high risk conflict zone but was &amp;ldquo;punished&amp;rdquo; for his uppity intelligence by getting a cushy Geneva job; and just his general portrayal as a heroic, super-smart, righteous hero in the mold of Jack Ryan.&lt;br/>&lt;br/>It&amp;rsquo;s actually funny because the meta of his &amp;ldquo;voice&amp;rdquo; - what it could (potentially) reveal about his character - reminded me very much of James Comey and John Dickerson, two other public figures who also first struck me as deeply, admirably ethical, and then that upstanding nobility was sort of complicated with a deeper feeling that they were also strangely vain about that same moral nobility? I remember when Trump called Comey a &amp;ldquo;showboat&amp;rdquo;, and how very outrageous that felt at the time, but then several months later, I was like, &amp;ldquo;you know, maybe he has a point&amp;rdquo;. Similarly, I love John Dickerson (who can&amp;rsquo;t!), but I&amp;rsquo;ve likewise noticed how cultivated that aura of righteous dude is; and how he must relish it!&lt;br/>&lt;br/>Which is funny! Because, from what I can tell, Snowden, Comey and Dickerson ARE righteous dudes! They DO embody high ethical standards! I guess I just have complicated feelings when it becomes apparent that THEY hero-worship themselves a bit too. I am, of course, speculating (especially about Dickerson, who seems least &amp;ldquo;showboaty&amp;rdquo;). &lt;br/>&lt;br/>Other writing stuff: Snowden&amp;rsquo;s early chapters on his upbringing in 1990s Maryland, as well as his descriptions of the early Internet, the Federal contracting industry, and the rise of social media, were his strongest. I highlighted several passages that were SO insightful (and I was going to give this book 5 stars!). His later chapters, and especially his attempt to weave his relationship with his girlfriend, Lindsay, throughout the rest of the book - felt strangely unbelievable?! Which is funny (this is nonfiction!), but the excerpts from her diaries just felt&amp;hellip; very similar to his voice!&lt;br/>&lt;br/>&lt;br/>&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/46223297" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Fun with git</title><link>https://www.angelaambroz.com/posts/fun_with_git/</link><pubDate>Wed, 16 Oct 2019 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/fun_with_git/</guid><description>&lt;p>Today, I was working through an old repo - &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/10/understanding_a_big_wide_codebase/" target="_blank">trying to understand what the hell had happened during its history&lt;/a> - when I thought, &amp;ldquo;I wish there was some way I could just &lt;em>watch&lt;/em> the git commits, like a movie, like a ghostly async pair programming exercise.&amp;rdquo;&lt;/p>
&lt;p>A quick google found me this: &lt;a href="https://gource.io/" target="_blank">gource.io&lt;/a>&lt;/p>
&lt;p>After some faffery around installing from source, I&amp;rsquo;ll save you the trouble and tell you that:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">brew install gource
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>worked fine (on my OSX).&lt;/p>
&lt;p>And now&amp;hellip; voila, some snippets from &lt;a href="https://github.com/pandas-dev/pandas/" target="_blank">&lt;code>pandas&lt;/code>&lt;/a>:&lt;/p>
&lt;p>You can jump around the timeline; you can pause time and explore. It seems like you can also click on people or files and follow them. One thing I don&amp;rsquo;t like is that jumping in time refreshes the screen - i.e. it doesn&amp;rsquo;t show you how big the project has become e.g. from 2009 to 2014. But there&amp;rsquo;s probably a way around that.&lt;/p>
&lt;p>Very, very cool.&lt;/p>
&lt;p>Now someone just needs to write a way to replay git commits in a fake pair programming environment.&lt;/p></description></item><item><title>Nobel Prize, Economics, 2019</title><link>https://www.angelaambroz.com/posts/nobel_prize_economics_2019/</link><pubDate>Wed, 16 Oct 2019 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/nobel_prize_economics_2019/</guid><description>&lt;p>Yesterday, the winners of the 2019 Nobel Prize in Economics were announced: &lt;a href="http://economics.mit.edu/faculty/eduflo" target="_blank">Esther Duflo&lt;/a>, &lt;a href="https://economics.mit.edu/faculty/banerjee/short" target="_blank">Abhijit Banerjee&lt;/a>, and &lt;a href="https://scholar.harvard.edu/kremer/home" target="_blank">Michael Kremer&lt;/a>.&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Esther_Duflo_-_Pop%21Tech_2009_-_001_%28cropped%29.jpg/384px-Esther_Duflo_-_Pop%21Tech_2009_-_001_%28cropped%29.jpg" alt="esther" />
&lt;/figure>
&lt;/p>
&lt;p>This was super exciting! I worked for Esther and Abhijit from 2009 to 2013; I never worked for Michael, though he was in a lot of seminars (and was often remarked on by us lowly minions for how both insightful and kind his comments always were). I like to say I was Esther&amp;rsquo;s lowly minion (Research Assistant) for a year, and then got promoted to chief minion (i.e. Research Manager, yay) for three more years. Those were salad days indeed!&lt;/p>
&lt;p>Their work has had a transformative effect on international development; working with them was also formative and special. A good overview of their work is &lt;a href="https://www.amazon.com/Poor-Economics-Radical-Rethinking-Poverty-ebook/dp/B007CI81IQ" target="_blank">Poor Economics&lt;/a>. Their organization - the &lt;a href="https://www.povertyactionlab.org" target="_blank">Abdul Latif Jameel Poverty Action Lab (J-PAL)&lt;/a> - also offers a &lt;a href="https://www.povertyactionlab.org/training/micromasters" target="_blank">MicroMasters on EdX&lt;/a>, if you want to go more in depth. The World Bank had a good blog post on Monday about &lt;a href="https://blogs.worldbank.org/impactevaluations/nobel-prize-development-rcts" target="_blank">their impact on the field at large&lt;/a>. A good overview of adjacent activities - the economics and development milieu in which their work can be situated - would be &lt;a href="https://www.amazon.com/dp/B00BVJG2LK/ref=dp-kindle-redirect?_encoding=UTF8&amp;amp;btkr=1" target="_blank">The Idealist&lt;/a> (about Jeffrey Sachs, another top academic - who incidentally Esther RAed for long ago! - whose work has suffered in reputation lately), &lt;a href="https://www.amazon.com/Undoing-Project-Friendship-Changed-Minds-ebook/dp/B01GI6S7EK/ref=sr_1_1?keywords=the&amp;#43;undoing&amp;#43;project&amp;amp;qid=1571254381&amp;amp;s=digital-text&amp;amp;sr=1-1" target="_blank">The Undoing Project&lt;/a> (about the &amp;ldquo;founding fathers&amp;rdquo; of behavioral economics, which informs a lot of DufloBanerjeeKremer&amp;rsquo;s microeconomic views), and &lt;a href="https://www.youtube.com/watch?v=aCv29JKmHNY" target="_blank">&lt;em>Inside Bill&amp;rsquo;s Brain&lt;/em> on Netflix&lt;/a> (the Gates Foundation is a big funder of J-PAL&amp;rsquo;s work).&lt;/p>
&lt;p>And Esther is, as always, remarkable as an individual: she&amp;rsquo;s the second woman to win the Nobel (which should embarrass the Nobel deciderers, honestly) and the youngest winner too (!).&lt;/p>
&lt;p>What wonderful news! Heartfelt congratulations to them!&lt;/p>
&lt;h2 class="relative group">Addendum
&lt;div id="addendum" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#addendum" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I wanted to add a very insightful Twitter thread that Nick Hagerty (a friend and former colleague, as well as former PhD advisee of Esther&amp;rsquo;s) wrote, which - I think - contextualizes just &lt;em>what&lt;/em> is so remarkable about Esther, Abhijit, and Michael:&lt;/p>
&lt;blockquote class="twitter-tweet" data-lang="en">&lt;p lang="en" dir="ltr">In earlier econ culture, certain great men held special wisdom that was inaccessible to others without their help.&lt;br>&lt;br>Esther and Abhijit (+ plenty of others) not only pulled back this curtain but also showed everyone ways to start figuring out what we CAN know (however narrowly).&lt;/p>&amp;mdash; Nick Hagerty (@hagertynw) &lt;a href="https://twitter.com/hagertynw/status/1183841972219301888?ref_src=twsrc%5Etfw">October 14, 2019&lt;/a>&lt;/blockquote>
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8">&lt;/script>
&lt;p>I agree.&lt;/p></description></item><item><title/><link>https://www.angelaambroz.com/posts/ghc19/</link><pubDate>Thu, 03 Oct 2019 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/ghc19/</guid><description>&lt;p>I&amp;rsquo;ve spent the past few days at &lt;a href="https://twitter.com/hashtag/ghc19?lang=en" target="_blank">#GHC19&lt;/a>, aka the &lt;a href="https://ghc.anitab.org/2019-attend/" target="_blank">2019 Grace Hopper Celebration&lt;/a> in Orlando, FL. I had heard about this conference for several years, and this was my first year attending.&lt;/p>
&lt;blockquote class="twitter-tweet" data-lang="en">&lt;p lang="en" dir="ltr">If someone says they can’t find enough women in tech to hire, encourage, promote, show them this picture of 25000 amazing women in tech and assure them that not all of them came to attend &lt;a href="https://twitter.com/hashtag/GHC19?src=hash&amp;amp;ref_src=twsrc%5Etfw">#GHC19&lt;/a> and there are more back home! 😉&lt;a href="https://twitter.com/hashtag/womenintech?src=hash&amp;amp;ref_src=twsrc%5Etfw">#womenintech&lt;/a> &lt;a href="https://twitter.com/hashtag/AnitaB?src=hash&amp;amp;ref_src=twsrc%5Etfw">#AnitaB&lt;/a> &lt;a href="https://twitter.com/hashtag/Equity?src=hash&amp;amp;ref_src=twsrc%5Etfw">#Equity&lt;/a> &lt;a href="https://twitter.com/hashtag/5050By2025?src=hash&amp;amp;ref_src=twsrc%5Etfw">#5050By2025&lt;/a> &lt;a href="https://t.co/YA77UD6oZq">pic.twitter.com/YA77UD6oZq&lt;/a>&lt;/p>&amp;mdash; Meenu Datta (@Me_Datta) &lt;a href="https://twitter.com/Me_Datta/status/1179585203695685632?ref_src=twsrc%5Etfw">October 3, 2019&lt;/a>&lt;/blockquote>
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8">&lt;/script>
&lt;h1 class="relative group">Thoughts and feelings
&lt;div id="thoughts-and-feelings" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#thoughts-and-feelings" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;ul>
&lt;li>It is a &lt;em>mega&lt;/em>-conference! &lt;strong>&lt;em>25,000 attendees!&lt;/em>&lt;/strong> 😱&lt;/li>
&lt;li>I felt like I was living in the last few panels of &lt;a href="https://www.goodreads.com/series/86528-y-the-last-man" target="_blank">Y: The Last Man&lt;/a>, i.e. a &lt;strong>world of women&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;p>&lt;span class="caption">&lt;a href="https://www.dccomics.com/comics/y-the-last-man-2002/y-the-last-man-60" target="_blank">Y: The Last Man, issue #60&lt;/a>&lt;/span>&lt;/p>
&lt;ul>
&lt;li>It was &lt;strong>super inspiring&lt;/strong>, more on the meta (&lt;em>yeah! ladies in tech!&lt;/em>) than on specific, technical talks. Though I did wrap up the conference with a long list of &lt;code>TODOs&lt;/code>: Julia, Go, Rust, Spark, maybe I should build that Clojure web app&amp;hellip;&lt;/li>
&lt;li>So apparently &lt;strong>company t-shirts are a thing&lt;/strong>; there were gangs of roving Googlers, Amazon(ians?), Facebookers, etc. This was similar to the family vacation t-shirts I saw in the Disney parks at night: Ambroz Disney Family Vacation 2019! Part of me considers it tacky; most of me hungers for such a t-shirt&amp;hellip;&lt;/li>
&lt;li>Speaking of &lt;strong>Disney&lt;/strong>, I completed Disney Tech&amp;rsquo;s &lt;strong>coding challenge&lt;/strong> and won a t-shirt! 🎉&lt;/li>
&lt;li>I also really enjoyed the challenge - where do I find more puzzles?!&lt;/li>
&lt;li>In other t-shirt news, I made (and had accepted) two &lt;strong>open source PRs&lt;/strong> - one on &lt;a href="https://github.com/papers-we-love/papers-we-love/pull/574" target="_blank">&lt;code>papers-we-love&lt;/code>&lt;/a> and one on &lt;a href="https://github.com/pandas-dev/pandas/pull/28742" target="_blank">&lt;code>pandas&lt;/code>&lt;/a>. This puts me at 50% towards &lt;a href="https://hacktoberfest.digitalocean.com" target="_blank">Digital Ocean&amp;rsquo;s Hacktoberfest&lt;/a> promise of:&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>make 4 PRs to open source projects
+
in October
+
be in the first 50k people to do this
=
get t-shirt
&lt;/code>&lt;/pre>&lt;p>LET IT BE KNOWN THAT I &lt;em>WILL&lt;/em> CODE FOR T-SHIRTS.&lt;/p>
&lt;h1 class="relative group">Some history
&lt;div id="some-history" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#some-history" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>Grace Hopper (1906-1992) was&amp;hellip;&lt;/p>
&lt;blockquote>
&lt;p>&amp;ldquo;&amp;hellip;an American computer scientist and United States Navy rear admiral. One of the first programmers of the Harvard Mark I computer, she was a pioneer of computer programming who invented one of the first linkers.&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;span class="caption">&lt;a href="https://en.wikipedia.org/wiki/Grace_Hopper" target="_blank">wiki&lt;/a>&lt;/span>&lt;/p>
&lt;/blockquote>
&lt;p>She, along with &lt;a href="https://en.wikipedia.org/wiki/Ada_Lovelace" target="_blank">Ada Lovelace (1815-1852)&lt;/a>, are kind of the matron saints of Women in Tech. They are eerrrrrywhere.&lt;/p>
&lt;p>I have many thoughts and feelings about Women in Tech. The shortest distillation is: I think we&amp;rsquo;re at an interesting point in history right now, and I&amp;rsquo;m hopeful. I also love being a Woman in Tech. I love my job. I love (and sometimes dread the future of?!) my career.&lt;/p>
&lt;p>We&amp;rsquo;re at the groundswell of a reaction against a &lt;a href="https://www.npr.org/sections/money/2014/10/21/357629765/when-women-stopped-coding" target="_blank">weird, Mad Men/marketing-driven gendering of tech&lt;/a> which started in the 80s and basically gatekept-with-a-padlock a generation of women (and thus a generation of minds) from an industry; &lt;em>right when it was getting so important, socio-economically (the dotcom bubble! the commercialization of the Internet! web 2.0! social media!).&lt;/em>&lt;/p>
&lt;p>So I&amp;rsquo;m glad that there are these big, grand, moneyed gestures that shout about diversity and inclusion from the convention center rooftops. Indeed! More women in tech! Keep women in tech! And I appreciate that there are lots of opportunities to increase the number of women in tech:&lt;/p>
&lt;ul>
&lt;li>scholarships! &lt;code>*&lt;/code>&lt;/li>
&lt;li>communities!
&lt;ul>
&lt;li>&lt;a href="https://www.pyladies.com/" target="_blank">PyLadies&lt;/a> &lt;code>*&lt;/code>&lt;/li>
&lt;li>&lt;a href="https://djangogirls.org/" target="_blank">DjangoGirls&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.railsbridge.org/" target="_blank">RailsBridge&lt;/a> &lt;code>*&lt;/code>&lt;/li>
&lt;li>&lt;a href="https://clojurebridge.org/" target="_blank">ClojureBridge&lt;/a> &lt;code>*&lt;/code>&lt;/li>
&lt;li>&lt;a href="https://girlswhocode.com/" target="_blank">Girls Who Code&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.womenwhocode.com/" target="_blank">Women Who Code&lt;/a> &lt;code>*&lt;/code>&lt;/li>
&lt;li>&lt;a href="https://anitab.org/systers/" target="_blank">Systers&lt;/a>!&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>codes of conduct for conferences and open source projects!&lt;/li>
&lt;/ul>
&lt;p>(I put an &lt;code>*&lt;/code> next to the ones I economically benefited from - as in, I either got a job, got better at my job, or just got plain ol&amp;rsquo; cash.)&lt;/p>
&lt;p>And so on. I think that&amp;rsquo;s great. I also think there are powerful economic reasons - both from the labor supply and labor demand sides - that make Women in Tech a very worthwhile objective indeed. Efficiency! From the labor demand side, &lt;a href="https://www.bls.gov/ooh/computer-and-information-technology/software-developers.htm" target="_blank">the need for software devs is expected to grow &amp;ldquo;much faster than average&amp;rdquo; - that is, 21% increase over the next ten years (as opposed to the average of 5%)&lt;/a>. From the labor supply side, I&amp;rsquo;m inspired by &lt;a href="https://scholar.harvard.edu/files/goldin/files/gender_equality.pdf" target="_blank">Claudia Goldin&amp;rsquo;s work noting that tech jobs - and any jobs that allow flexibility in how you get your work done - can close the wage gap&lt;/a>.&lt;/p>
&lt;h1 class="relative group">Thanks
&lt;div id="thanks" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#thanks" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>Speaking of moneyed gestures, thanks to&lt;/p>
&lt;ul>
&lt;li>the 🐝 &lt;a href="https://www.cc.gatech.edu/" target="_blank">College of Computing at Georgia Tech&lt;/a> 🐝&lt;/li>
&lt;li>and my employer, &lt;a href="https://www.optoro.com/" target="_blank">Optoro&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>who provided me with the funds and the opportunity to attend this year. It was a real privilege!&lt;/p></description></item><item><title>Chief Yak Shaver</title><link>https://www.angelaambroz.com/posts/chief_yak_shaver/</link><pubDate>Thu, 05 Sep 2019 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/chief_yak_shaver/</guid><description>&lt;p>Here&amp;rsquo;s a bunch of completely random stuff I learned these past few days, thanks to a devilishly borked up bork I fell into while trying to do &lt;em>what I thought&lt;/em> was an easy task:&lt;/p>
&lt;blockquote>
&lt;p>Just set up CI with some super basic tests on a Rails app I&amp;rsquo;m writing.&lt;/p>
&lt;/blockquote>
&lt;p>So-called &amp;ldquo;easy task&amp;rdquo; ate up my whole week, as I shaved yaks in a variety of domains I have [at present] a very limited understanding of:&lt;/p>
&lt;ul>
&lt;li>Ruby&lt;/li>
&lt;li>Ruby environments&lt;/li>
&lt;li>Ruby on Rails&lt;/li>
&lt;li>Docker&lt;/li>
&lt;li>Continuous integration testing, aka CI&lt;/li>
&lt;li>Gitlab&amp;rsquo;s implementation of CI, via Docker&lt;/li>
&lt;/ul>
&lt;p>I am presuming that my specific problem will impact no one ever, and that &lt;em>its content&lt;/em> will be of limited interest to most everyone, except maybe &amp;ndash;&lt;/p>
&lt;p>&lt;span class="caption">&lt;a href="https://xkcd.com/979/" target="_blank">xkcd: wisdom of the ancients&lt;/a>&lt;/span>&lt;/p>
&lt;p>But what I would like to take you on is my, ahem, &lt;strong>emotional journey&lt;/strong> here, people, because it really embodied one of the things I adore - and sometimes despair at - in tech: tenacity, grit, self-teaching, focus. AKA shaving the yak.&lt;/p>
&lt;blockquote>
&lt;h4 class="relative group">yak shaving (uncountable) - Noun
&lt;div id="yak-shaving-uncountable---noun" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#yak-shaving-uncountable---noun" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Any apparently useless activity which, by allowing you to overcome intermediate difficulties, allows you to solve a larger problem.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>I was doing a bit of &lt;strong>yak shaving&lt;/strong> this morning, and it looks like it might have paid off.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;span class="caption">&lt;a href="https://en.wiktionary.org/wiki/yak_shaving" target="_blank">wiktionary&amp;rsquo;s entry on yak shaving&lt;/a>&lt;/span>&lt;/p>
&lt;p>The thing about shaving yaks is that, crucially, it &lt;em>feels useless&lt;/em> while you&amp;rsquo;re doing it. You&amp;rsquo;re banging your head against a wall, there are perhaps imperceptible cracks in the wall, you have a thousand StackOverflow tabs open in your browser, and you generally feel like you are WASTING YOUR DAYS. At least, that&amp;rsquo;s how I felt.&lt;/p>
&lt;p>But I did break through the wall!&lt;/p>
&lt;p>I mean, it&amp;rsquo;s still all broken, but now the pieces are comprehensible and I&amp;rsquo;ll just spend tomorrow fixing them, one by one. But the main, confusing, confounding, uber-borked, non-deterministic-computing-makes-no-sense yak has been shaved. I Fixed The Thing.&lt;/p>
&lt;p>So let&amp;rsquo;s talk, first, briefly, about what the thing was and the fix.&lt;/p>
&lt;p>Then, let us speak of the journey.&lt;/p>
&lt;h2 class="relative group">The thing that I wanted to do
&lt;div id="the-thing-that-i-wanted-to-do" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-thing-that-i-wanted-to-do" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Context:&lt;/p>
&lt;ul>
&lt;li>I have a very simple, very basic Rails app.&lt;/li>
&lt;li>It is on &lt;a href="https://about.gitlab.com/" target="_blank">GitLab&lt;/a>.&lt;/li>
&lt;li>It has 2 very simple, very basic tests.&lt;/li>
&lt;li>I ran the &lt;a href="https://rspec.info/" target="_blank">&lt;code>rspec&lt;/code>&lt;/a> testing framework locally. It was fine.&lt;/li>
&lt;li>I thought I should use &lt;a href="https://about.gitlab.com/product/continuous-integration/" target="_blank">GitLab&amp;rsquo;s fancy continuous integration uh&amp;hellip; integration&lt;/a> and add a &lt;code>.gitlab-ci.yml&lt;/code> file which basically said: hey GitLab, gimme Ruby version 2.5.1, bundle install from my &lt;code>Gemfile.lock&lt;/code>, and let&amp;rsquo;s run that basic &lt;code>rspec&lt;/code>, eh?&lt;/li>
&lt;/ul>
&lt;p>Reader, it borked on step 2 (bundle install).&lt;/p>
&lt;h2 class="relative group">The thing that stopped me
&lt;div id="the-thing-that-stopped-me" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-thing-that-stopped-me" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The &lt;em>way&lt;/em> it borked was dastardly and weird. Basically,&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">$ gem install bundler -v &lt;span class="k">$(&lt;/span>grep -A &lt;span class="m">1&lt;/span> &lt;span class="s2">&amp;#34;^BUNDLED\ WITH&lt;/span>$&lt;span class="s2">&amp;#34;&lt;/span> Gemfile.lock &lt;span class="p">|&lt;/span> awk &lt;span class="s1">&amp;#39;NR == 2 { print $1 }&amp;#39;&lt;/span>&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Successfully installed bundler-2.0.1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">1&lt;/span> gem installed
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ gem list bundler
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">bundler &lt;span class="o">(&lt;/span>2.0.1, 1.16.6, default: 1.16.2&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ ruby -v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ruby 2.5.1p57 &lt;span class="o">(&lt;/span>2018-03-29 revision 63029&lt;span class="o">)&lt;/span> &lt;span class="o">[&lt;/span>x86_64-linux&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ bundle _2.0.1_ install
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">/usr/local/lib/ruby/site_ruby/2.5.0/rubygems.rb:289:in &lt;span class="sb">`&lt;/span>find_spec_for_exe&lt;span class="s1">&amp;#39;: Could not find &amp;#39;&lt;/span>bundler&lt;span class="s1">&amp;#39; (1.16.6) required by `$BUNDLER_VERSION`. (Gem::GemNotFoundException)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">To update to the lastest version installed on your system, run `bundle update --bundler`.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">To install the missing version, run `gem install bundler:1.16.6`
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> from /usr/local/lib/ruby/site_ruby/2.5.0/rubygems.rb:308:in `activate_bin_path&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> from /usr/local/bundle/bin/bundle:23:in &lt;span class="sb">`&lt;/span>&amp;lt;main&amp;gt;&lt;span class="err">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So many questions here. SO MANY.&lt;/p>
&lt;ul>
&lt;li>Main question: Why does it complain about &lt;code>bundler 1.16.6&lt;/code> when I (a) specifically installed version 2.0.1 (&lt;code>gem install blah&lt;/code>), and (b) specifically used that version too (&lt;code>bundle _2.0.1_ install&lt;/code>)? (FWIW, when I did plain &lt;code>bundle install&lt;/code>, it said I needed to use Bundler &amp;gt;2. 🤦‍♀️)&lt;/li>
&lt;li>Why is my &lt;code>site_ruby&lt;/code> filepath pointing to &lt;code>2.5.0&lt;/code> when I specifically pulled the &lt;code>2.5.1&lt;/code> Ruby from &lt;a href="https://hub.docker.com/_/ruby" target="_blank">Docker hub&lt;/a>? And it says I&amp;rsquo;m using &lt;code>2.5.1&lt;/code> when I check &lt;code>ruby -v&lt;/code>?&lt;/li>
&lt;li>Why does &lt;code>gem list bundler&lt;/code> tell me I have (a) a &lt;code>default&lt;/code> version of the gem (what does this mean?) and (b) &lt;em>that &lt;code>1.16.6&lt;/code>, the thing it later complains about, is also installed????&lt;/em>&lt;/li>
&lt;/ul>
&lt;p>I was tearing my hair out here. I was googling like mad. I was facing what can only be described as a deep Zen koan-like test of my patience and resolve and sanity. I &lt;em>suspected&lt;/em> something was going on with Ruby environments (that 2.5.0 vs. 2.5.1 thing? those Bundler versions?), I &lt;em>wanted&lt;/em> to access the Docker container directly but - dash! - I couldn&amp;rsquo;t figure out a way, because I was using the (incidentally normally very useful) &lt;a href="https://docs.gitlab.com/runner/" target="_blank">&lt;code>gitlab-runner&lt;/code> command line tool&lt;/a> and what the heck does &lt;em>that&lt;/em> do anyway!?! It definitely spins up a Docker container but then, well, kills it as soon as it&amp;rsquo;s done. Dash and blast!&lt;/p>
&lt;h2 class="relative group">The stuff I learned along the way to fixing this
&lt;div id="the-stuff-i-learned-along-the-way-to-fixing-this" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-stuff-i-learned-along-the-way-to-fixing-this" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Here&amp;rsquo;s some useful TILs from this terrible ordeal:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://docs.gitlab.com/runner/" target="_blank">&lt;code>gitlab-runner&lt;/code>&lt;/a> is a very useful way to &lt;em>not&lt;/em> spam your GitLab commit histories, i.e. not embarrass yourself in front of your colleagues.&lt;/li>
&lt;li>&lt;a href="https://docs.gitlab.com/ee/ci/interactive_web_terminal/index.html#doc-nav" target="_blank">Interactive web terminals&lt;/a> are a way to pause and shell into the online CI. Useful! Not so useful locally, but oh well&amp;hellip;&lt;/li>
&lt;li>&lt;a href="https://github.com/bundler/bundler/issues/7107" target="_blank">You cannot unset and reset the default &lt;code>bundler&lt;/code> gem. It is forbidden.&lt;/a> Why!? How?!&lt;/li>
&lt;li>&lt;a href="https://github.com/docker-library/ruby/issues/194" target="_blank">Bundler is kinda broken in &lt;em>one specific version&lt;/em> of the Docker Ruby image.&lt;/a> Aw, come on, man.&lt;/li>
&lt;li>You can replicate the above error (i.e. the one from my error log above, and mentioned in the GitHub issue in #4) by doing:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">❯ docker pull ruby:2.5.1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">❯ docker run -it --rm ruby:2.5.1 bash
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">root@7b17219881e3:/# bundle install
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Could not locate Gemfile
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">root@7b17219881e3:/# bundle -v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Bundler version 1.16.6
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So here I had a solution! That Docker ruby image wanted bundler 1.16.6, it &lt;em>neeeeded it&lt;/em>, but the &lt;code>Gemfile.lock&lt;/code> was insisting on 2.0.1. Fine. Let&amp;rsquo;s change the &lt;code>Gemfile.lock&lt;/code> file.&lt;/p>
&lt;ol start="6">
&lt;li>You can change the Bundler version needed to install your app - a version which is specified in the &lt;code>Gemfile.lock&lt;/code> file (&lt;a href="https://stackoverflow.com/a/6927553" target="_blank">created by whatever version of Bundler you have locally&lt;/a>) - by (a) removing the version number after &lt;code>BUNDLED WITH&lt;/code> (but keeping the &lt;code>BUNDLED WITH&lt;/code>!) and (b) running &lt;code>bundle _version-you-want_ install&lt;/code>. Thanks, &lt;a href="https://www.aloucaslabs.com/miniposts/how-to-install-and-bundle-your-rails-application-with-a-specific-bundler-version" target="_blank">aloucaslabs post&lt;/a>! I changed this to 1.16.6 and - voila! - everyone was happy. Docker was happy. Bundler was happy. And Rails was happy. (Well, Rails was mostly happy.)&lt;/li>
&lt;/ol>
&lt;h2 class="relative group">The journey
&lt;div id="the-journey" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-journey" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>So this sort of thing - falling into a bork hole - happens once every, oh, month or two? Maybe more infrequently. It happens when your service has a weird bug-out, some unexpected behavior. Or when your data looks weird. Or when, as this time, you&amp;rsquo;re building something new and have the hubris to think that &amp;ldquo;oh this&amp;rsquo;ll just take a minute&amp;hellip;&amp;rdquo;&lt;/p>
&lt;p>And, boy, it is an emotional journey. Namely, it&amp;rsquo;s an exercise in &amp;ndash;&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://media.giphy.com/media/Lf3alZIuS2AP6/giphy.gif" alt="rodeo clowns" />
&lt;/figure>
&lt;/p>
&lt;p>&amp;ndash; yes, TRUE GRIT.&lt;/p>
&lt;p>Many a moment did I despair and think, &amp;ldquo;oh let&amp;rsquo;s just forget setting this up, who will know&amp;rdquo; and many an excuse did I find, &amp;ldquo;oh i have more important DATA TO SCIENCE, what am i spending all these days on this for&amp;rdquo;.&lt;/p>
&lt;p>But I reminded myself of previous yak shaving expeditions that were similarly dire and similarly resolved, and how indeed sweet that victory was. And how much was learned! So I persevered. And also, of course, another nice thing that programming does to you is &lt;em>make you addicted to puzzling things out&lt;/em> - as one part of me despaired and found reasons to give up, the other part just wanted to frickin&amp;rsquo; figure it out. AND I DID. And that boost is addictive. So: hooray!&lt;/p>
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/wVEiskNv1hs" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen>&lt;/iframe></description></item><item><title>Recursive SQL queries</title><link>https://www.angelaambroz.com/posts/recursive_sql_queries/</link><pubDate>Thu, 13 Jun 2019 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/recursive_sql_queries/</guid><description>&lt;p>Did you know that SQL queries can be recusive? &lt;em>I didn&amp;rsquo;t!&lt;/em> Now I do. It&amp;rsquo;s glorious.&lt;/p>
&lt;h2 class="relative group">The problem
&lt;div id="the-problem" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-problem" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I had some data in the following format:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>thing&lt;/th>
&lt;th>sub_thing_id&lt;/th>
&lt;th>start_time&lt;/th>
&lt;th>end_time&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>1&lt;/td>
&lt;td>Sep 1&lt;/td>
&lt;td>Sep 3&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>2&lt;/td>
&lt;td>Sep 1&lt;/td>
&lt;td>Sep 7&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>And I &lt;em>wanted&lt;/em> it in the following format:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>thing&lt;/th>
&lt;th>date&lt;/th>
&lt;th>number_of_sub_things&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>Sep 1&lt;/td>
&lt;td>2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>Sep 2&lt;/td>
&lt;td>2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>Sep 3&lt;/td>
&lt;td>2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>Sep 4&lt;/td>
&lt;td>1&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>Sep 5&lt;/td>
&lt;td>1&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>Sep 6&lt;/td>
&lt;td>1&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>Sep 7&lt;/td>
&lt;td>1&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>How do?!&lt;/p>
&lt;h2 class="relative group">The solution: A recursive common table expression
&lt;div id="the-solution-a-recursive-common-table-expression" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-solution-a-recursive-common-table-expression" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Ah ha!&lt;/p>
&lt;blockquote>
&lt;p>A recursive CTE allows you to join all the levels of a hierarchy without knowing in advance how many levels there are.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;ul>
&lt;li>&lt;a href="https://docs.snowflake.net/manuals/user-guide/queries-cte.html#what-is-a-cte" target="_blank">Snowflake docs&lt;/a>&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;p>tl;dr, the query that worked was:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">select&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">thing&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">to_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">start_time&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">date&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">count&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">number_of_sub_things&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">with&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">cte&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">select&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">thing&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">sub_thing&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">start_time&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">end_time&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">some_wide_table&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">where&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">start_time&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">is&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">not&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">null&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">union&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">all&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">select&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">thing&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">sub_thing&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">dateadd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">day&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">start_time&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">end_time&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">cte&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">where&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">to_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">start_time&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">end_time&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">select&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">cte&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">group&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">by&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">order&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">by&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dte&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">asc&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But whaaat is happening here? I shall explain:&lt;/p>
&lt;ol>
&lt;li>First, create a recursive common table expression (CTE): &lt;code>(with cte ... from cte) as exp&lt;/code>&lt;/li>
&lt;li>In that CTE, create your &amp;ldquo;&lt;a href="https://docs.snowflake.net/manuals/user-guide/queries-cte.html#recursive-ctes-and-hierarchical-data" target="_blank">anchor clause&lt;/a>&amp;rdquo; (&lt;code>select thing ... from some_wide_table&lt;/code>) and &lt;code>union all&lt;/code> it to your &amp;ldquo;recursive clause&amp;rdquo; (&lt;code>select thing ... from cte&lt;/code>). Your anchor clause is the first, base set of rows you will be comparing your next &lt;code>select&lt;/code> statement against. Your recursive clause &lt;em>adds its resulting rows back to that base&lt;/em>, and then compares &lt;em>that&lt;/em> new &amp;ldquo;anchor&amp;rdquo; against the &lt;em>same&lt;/em> &amp;ldquo;recursive clause&amp;rdquo; &lt;code>select&lt;/code> statement.&lt;/li>
&lt;li>It keeps doing this until the &lt;code>where to_date(start_time) &amp;lt;= (to_date(end_time)-1))&lt;/code> statement is no longer satisfied. So it&amp;rsquo;s (kinda) recuuuursive! Magic! And, like all recursive functions, there is a risk that you fall into an infinite loop if your &lt;code>where&lt;/code> clause never catches.&lt;/li>
&lt;li>Once you&amp;rsquo;ve completed recursing around, you &lt;code>select * from cte&lt;/code> - this is selecting all the resulting rows that were found as the anchor and recursive clauses did their dance.&lt;/li>
&lt;li>I then needed to &lt;code>group by&lt;/code> the top-level thing and &lt;code>count(*)&lt;/code> how many sub-things were present on each date.&lt;/li>
&lt;/ol>
&lt;p>Voila!&lt;/p>
&lt;h2 class="relative group">The next problem
&lt;div id="the-next-problem" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-next-problem" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>So I actually ended up &lt;em>not&lt;/em> being able to use this, because I wanted to do this arbitrary recursion over thousands of dates, millions of things, and tens of millions of sub-things. I quickly got to a &lt;code>max iteration count reached&lt;/code> error from the database; a safety mechanism it has in place to prevent infinite recursions. It wasn&amp;rsquo;t infinite, but it was certainly a bit of a combinatorial explosion.&lt;/p>
&lt;p>So what do now?!&lt;/p>
&lt;p>tl;dr: There was a much more efficient, non-recursive way to do this. Basically, make a table of dates on the fly and join against that. D&amp;rsquo;oh.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">select&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">thing&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">to_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">this_date&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dte&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">count&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">number_of_sub_things&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">select&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">thing&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">sub_thing&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">dates&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">this_date&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">some_wide_table&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">right&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">join&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">select&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">dateadd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">day&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">seq4&lt;/span>&lt;span class="p">(),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;2011-01-01&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">this_date&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">from&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">table&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">generator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">rowcount&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">9&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">365&lt;/span>&lt;span class="p">)))&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">dates&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">on&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">to_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">start_timee&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">to_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dates&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">this_date&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">and&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">to_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">end_time&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">to_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dates&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">this_date&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">as&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">group&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">by&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I don&amp;rsquo;t love this solution, namely because I need to decide (and hard-code) the range of dates to compare against. For now, I&amp;rsquo;m creating a list of dates from &lt;code>2011-01-01&lt;/code> to 9 years hence (&lt;code>9*365&lt;/code>). It feels hacky. But it took a fraction of the time and no combinatorial problems! So it&amp;rsquo;s good enough.&lt;/p></description></item><item><title>It's amazing what you can get done</title><link>https://www.angelaambroz.com/posts/its_amazing_what_you_can_get_done_when/</link><pubDate>Mon, 10 Jun 2019 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/its_amazing_what_you_can_get_done_when/</guid><description>&lt;p>Recently, I realized I was doing the same thing three different ways. Namely, I was trying to practice mindfulness - and, while I was using different strategies (1) for work, (2) for home, and (3) for &amp;ldquo;personal development&amp;rdquo;, it was all the same thing. Here&amp;rsquo;s some stuff about my work-related mindfulness strategies.&lt;/p>
&lt;h1 class="relative group">The problem: work in the Age of Distraction
&lt;div id="the-problem-work-in-the-age-of-distraction" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-problem-work-in-the-age-of-distraction" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>What with Slack and slow SQL queries, there has been endless opportunity for me to be distracted - and my brain has generally turned into a big, thin mushy goo, as I have flitted from task to task, nudging everything forward but not thinking &lt;em>deeply&lt;/em> about any of it.&lt;/p>
&lt;h1 class="relative group">The solution: Tomato time + turning everything off
&lt;div id="the-solution-tomato-time--turning-everything-off" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-solution-tomato-time--turning-everything-off" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>After &lt;a href="https://www.goodreads.com/review/show/2617441190?book_show_action=false&amp;amp;from_review_page=1" target="_blank">reading Cal Newport&amp;rsquo;s Deep Work&lt;/a> and shaking my Spear of Social Justice at it, I decided to implement the basic idea: &lt;strong>focused work&lt;/strong>. I downloaded a &lt;a href="https://en.wikipedia.org/wiki/Pomodoro_Technique" target="_blank">pomodoro timer&lt;/a> (after briefly debating buying an actual, vintage, Italian tomato-shaped kitchen timer because AESTHETICS) and got in the habit of closing everything (Slack, email, phone, random browser tabs) during those 25-minute chunks.&lt;/p>
&lt;p>Reader, I got so much more work done.&lt;/p>
&lt;p>And better work! Suddenly, using my ACTUAL BRAIN and giving tasks my full attention, solutions would pop and I had all sorts of ideas and work just generally felt like a calm, rich, rewarding activity. So that was great. A+.&lt;/p>
&lt;h1 class="relative group">The challenges: but [my SQL query | Docker | grid searching] is &lt;em>so sloooow&lt;/em>
&lt;div id="the-challenges-but-my-sql-query--docker--grid-searching-is-_so-sloooow_" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-challenges-but-my-sql-query--docker--grid-searching-is-_so-sloooow_" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>The big issue I have is that some of my work tasks, by their very nature, occupy my computer for a very long time. They are computationally slow.&lt;/p>
&lt;p>For example: a big, complex SQL query on millions of rows. For example: a machine learning grid search. What to do? What if I&amp;rsquo;m in the dead middle of a tomato-time when some computationally-intensive task kicks off, and I&amp;rsquo;m just left staring at my screen?&lt;/p>
&lt;p>Sometimes, when my will has been strong and my intentions extra-pure, I&amp;rsquo;ve allowed the dragging seconds of boredom to wash clean my mind. &lt;em>Sometimes&lt;/em> this has led to some &amp;ldquo;ah ha!&amp;rdquo; moments - e.g. that query could be made much more efficient! there&amp;rsquo;s probably a better way to do this! That&amp;rsquo;s excellent. But it takes extra-strong willpower.&lt;/p>
&lt;p>Otherwise, I nudge forward on some work-related book (e.g. &lt;a href="https://www.statisticsdonewrong.com/" target="_blank">Statistics Done Wrong&lt;/a>). Something to keep things quiet, and not scattered (i.e. not checking my phone).&lt;/p></description></item><item><title>OMSCS Course review- Knowledge-based Artificial Intelligence</title><link>https://www.angelaambroz.com/posts/omscs_course_review_knowledgebased_artificial_intelligence/</link><pubDate>Mon, 07 Jan 2019 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/omscs_course_review_knowledgebased_artificial_intelligence/</guid><description>&lt;p>First OMSCS course is complete!&lt;/p>
&lt;blockquote>
&lt;p>Disclaimer: This review applies to the &lt;strong>Fall 2018&lt;/strong> instance of &lt;a href="http://www.omscs.gatech.edu/cs-7637-knowledge-based-artificial-intelligence-cognitive-systems" target="_blank">CS7367: KBAI&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 class="relative group">tldr
&lt;div id="tldr" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#tldr" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>So, tldr, I thought this course was fine.&lt;/p>
&lt;p>I didn&amp;rsquo;t know much about the topic - knowledge-based AI systems - before signing up, but it sounded intriguing, like maybe it would combine some sort of sublimated Oliver Sacksian neuroscience wonder with programming fun.&lt;/p>
&lt;p>It was &lt;em>sorta&lt;/em> like that, but I honestly ended up finding the methods of KBAI frustratingly vague. I mean, people get grumpy about the inscrutability of neural nets, and AI modeled on human-like cognitive systems certainly has a contrasting appeal. But &lt;em>coding&lt;/em> such systems? Especially when we don&amp;rsquo;t have a full understanding of how human cognition works? Oooof.&lt;/p>
&lt;p>The structure of the course was great, though I felt an increasing disconnect between the &lt;code>project&lt;/code> side of things vs. the &lt;code>everything else&lt;/code> side of things. That said, it was a good, gentle intro to the OMSCS program overall.&lt;/p>
&lt;h2 class="relative group">Structure
&lt;div id="structure" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#structure" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Twenty-six lectures&lt;/strong> on Udacity, each about 45-90 minutes long.&lt;/li>
&lt;li>&lt;strong>Three homeworks&lt;/strong>, which covered at least one lecture topic as well as some open-ended, creative stuff about, &amp;ldquo;hey, so how about that crazy AI, eh?!&amp;rdquo;. If you hate writing, you will be sad. If you love writing, these are awesome!&lt;/li>
&lt;li>&lt;strong>Three exams&lt;/strong>, which cover the lecture material and I found very &lt;em>ugghh&lt;/em>. These were timed, proctored using an Orwellian webcam auto-proctor (heh), and generally relied on tricksy wordings of concepts as opposed to creative applications of concepts. I liked the exams the least, and felt they contributed to my learning the least. (That said, one of the co-instructors, Dr. David Joyner, released some very cool post-exam analyses after each one, which seems to indicate I may have been an outlier?)&lt;/li>
&lt;li>&lt;strong>One zany project&lt;/strong>. This was the heart and meat of the course for me; it was the place I learned the most. Basically, we had to build - from scratch (!), and in the language of our choosing (either Python or Java) - an AI agent that could parse visual intelligence tests of the following kind:&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Raven_Matrix.svg/500px-Raven_Matrix.svg.png" alt="rpm" />
&lt;/figure>
&lt;/p>
&lt;p>If that sounds daunting, oh man, you bet it was! The project was an emotional roller coaster of &amp;ldquo;omg how do i even&amp;rdquo; and &amp;ldquo;OMG IT&amp;rsquo;S WORKING &lt;em>IT&amp;rsquo;S WORKING&lt;/em>&amp;rdquo;.&lt;/p>
&lt;p>The project work felt very distinct - even disconnected - from what the lectures were telling me. I basically had to be resourceful and self-teach stuff like (a) how do you parse images in Python (we were allowed to use the &lt;a href="https://pillow.readthedocs.io/en/stable/" target="_blank">&lt;code>Pillow&lt;/code>&lt;/a> library - a basic visual parsing library - but not the more advanced, computer visiony &lt;a href="https://opencv.org/" target="_blank">&lt;code>OpenCV&lt;/code>&lt;/a>), (b) once you &amp;ldquo;see&amp;rdquo; the image, how do you compare images, and (c) how do you develop generalized logic to compare arbitrary transitions and patterns.&lt;/p>
&lt;p>It was madness!&lt;/p>
&lt;p>And a lot of fun. My guesstimate is that the class - which had ~400 people in it - had a long-tail distribution of a few people who put &lt;em>many, many&lt;/em> hours into developing near-perfect agents and a &lt;em>lot&lt;/em> of people who put in a decent number of hours to get a decent performance. I was more in the fat part of the distribution (yo, I got a life to live here); my agent performed well-enough (it crossed each increasingly difficult hurdle as we faced harder and harder visual IQ tests, but it often just barely crossed), and I did a fair amount of love/hate refactoring throughout.&lt;/p>
&lt;p>I do think I missed out on some &amp;ldquo;ah ha!&amp;rdquo; moments when I could truly blend the lectures&amp;rsquo; vague-feeling &amp;ldquo;let&amp;rsquo;s model incremental concept learning!&amp;rdquo; with my AI agent (which mostly used heuristics). But I just didn&amp;rsquo;t have the time to make that leap into KBAI nirvana. (And I&amp;rsquo;m guesstimating I put about ~20 hours total into the agent?)&lt;/p>
&lt;h2 class="relative group">Effort
&lt;div id="effort" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#effort" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Which brings me to effort! So this was less effort than any of the Harvard Extension School classes that I&amp;rsquo;ve taken. And thank God for that, because those classes had me doing ~20 hours/week of problem sets and, man, that shit is unsustainable. (And yes, I did learn a lot, but I do think there were marginal decreasing returns to some of those p-sets.)&lt;/p>
&lt;p>I&amp;rsquo;d guesstimate that I spent, on average, about 7-10 hours/week on this course, and I wasn&amp;rsquo;t super disciplined or time-efficient. I watched the lectures at about 1.25x - 1.5x speed, which was normally fine. I read a little bit of &lt;a href="https://www.amazon.com/Artificial-Intelligence-3rd-Winston/dp/0201533774" target="_blank">Winston&lt;/a>. I was a speed-demon on the exams and homeworks, and I spent the bulk of my time agonizing over the project. This was fine. Again, I probably could have invested more and gotten more out of it, but - well - the thing I love about the OMSCS overall is its flexibility.&lt;/p>
&lt;h2 class="relative group">Would I recommend this?
&lt;div id="would-i-recommend-this" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#would-i-recommend-this" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>YES for &lt;strong>first semester OMSCS students&lt;/strong>. Dr. Joyner is a great edtech educator, and he seems very dedicated to running these courses well. I think any of his courses - like this, &lt;a href="https://www.omscs.gatech.edu/cs-6750-human-computer-interaction" target="_blank">CS 6750: Human-Computer Interaction&lt;/a>, or &lt;a href="https://www.omscs.gatech.edu/cs-6460-educational-technology" target="_blank">CS 6460: Educational Technology&lt;/a> - is a great &amp;ldquo;intro&amp;rdquo; to the OMSCS overall. I want to actually take his other courses just because I&amp;rsquo;m so confident they&amp;rsquo;ll be so well-run.&lt;/li>
&lt;li>NO for &lt;strong>people interesting in machine learning&lt;/strong>, since it felt like this type of AI isn&amp;rsquo;t really practiced anymore. Sometimes it&amp;rsquo;s valuable to see a contrasting methodology, even if you never use it, but I found much of the lecture material to be so far in the camp of &amp;ldquo;I will definitely never do it this way&amp;rdquo; that it got pretty existentially doubtful. Like, why? WHYYYYY?&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Up next?
&lt;div id="up-next" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#up-next" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;m pumped for a bunch of courses. Oddly, the &lt;strike>Digital Wolf of Wall Street&lt;/strike> &lt;a href="https://www.omscs.gatech.edu/cs-7646-machine-learning-trading" target="_blank">Machine Learning for Trading&lt;/a> has me pretty pumped.&lt;/p></description></item><item><title>Best books of 2018</title><link>https://www.angelaambroz.com/posts/best_books_of_2018/</link><pubDate>Mon, 31 Dec 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/best_books_of_2018/</guid><description>&lt;p>Yay! It&amp;rsquo;s my favorite time of year: the &lt;code>let's reflect&lt;/code> time of year! The &lt;code>best books of [year]&lt;/code> time of year! YAAAAY.&lt;/p>
&lt;h2 class="relative group">Overall stats
&lt;div id="overall-stats" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#overall-stats" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Alright. This year, I read &lt;a href="https://www.goodreads.com/user_challenges/10313328" target="_blank">73 books&lt;/a>. Of these, 24 (33%) were by women and 15 (21%) by writers of color. Pretty bad stats, given the actual proportions of who&amp;rsquo;s writing stuff in English. Once again, I disproportionately read the work of white dudes.&lt;/p>
&lt;p>In terms of how I decided what to read, I mostly followed my nose; where by &amp;ldquo;following my nose&amp;rdquo;, I mean that it was a combination of what the algorithms and the zeitgeist fed me, as mediated by my long-term reading goals (weighted low) and my short-term mood when selecting what to read next (weighted very high). Maybe I&amp;rsquo;ll be more intentional about reading next year.&lt;/p>
&lt;h2 class="relative group">Most influential
&lt;div id="most-influential" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#most-influential" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I read a handful of books early in 2018 that I basically spent the rest of year citing and referencing as much as possible. In all these cases, I was surprised I had read them &lt;em>this&lt;/em> year, since they had become so completely absorbed in my thinking - they felt like foundational texts from long ago. These were:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Jonathan Haidt&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2277322034?book_show_action=false&amp;amp;from_review_page=1" target="_blank">The Righteous Mind&lt;/a>, which Explains Everything About Politics. Politics are &lt;em>very&lt;/em> on my mind these days, thanks to the 2016 election and the hyper-polarization we seem to be experiencing in the US, Italy, Germany, UK, Tanzania, India&amp;hellip; okay, everywhere the light touches, Simba. Haidt&amp;rsquo;s book is a great combination of rigorous experimental evidence and social psychology to explain why us hairless apes get so funky and intense about politics (and other tribal affiliations). I really enjoyed his takeaway of the &amp;ldquo;five moral tastes&amp;rdquo;, and how left-leaning Western humans have lost the ability to taste all five. I can&amp;rsquo;t make myself taste authority! AND YOU CAN&amp;rsquo;T MAKE ME.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Tony Judt&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2211487036?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Postwar&lt;/a>. I didn&amp;rsquo;t think I needed a postwar Europe explainer. Now I think EVERYONE NEEDS IT AND EVERYONE NEEDS THIS ONE. This reframed my understanding of World War 2 and many European countries&amp;rsquo; histories (especially Austria, France, the Netherlands). It provided useful kick-in-the-butts around certain well-known periods as 1968 and the Thatcher Years. It was dispiriting. It destroyed myths. It was so good.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Tim Wu&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2285247834?book_show_action=false&amp;amp;from_review_page=1" target="_blank">The Attention Merchants&lt;/a>. A wonderful explainer of the driving economic forces behind our attention economy and, as Bruce Schneier calls it, surveillance capitalism. The roots go deep. Delete your Facebook, for the love of God, it&amp;rsquo;s the &lt;a href="http://www.angelaambroz.com/blog/posts/2018/May/18/social_media_is_cigarettes/" target="_blank">cigarettes of the modern era&lt;/a>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Charles Mann&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2375940114?book_show_action=false&amp;amp;from_review_page=1" target="_blank">1491&lt;/a>. I put Charles Mann and James Scott in the same mental bookshelf: they write God&amp;rsquo;s-eye-view sweeping, hyper-macro interpretations of history and politics. They&amp;rsquo;ve both made me totally reframe my understanding of big-deal things like the state (via James Scott&amp;rsquo;s &lt;a href="https://www.goodreads.com/book/show/20186.Seeing_Like_a_State?from_search=true" target="_blank">Seeing Like a State&lt;/a>) and, in 1491&amp;rsquo;s case, the New World. I learned &lt;em>so much&lt;/em> about the pre-Colombus Americas via this book. I was inspired about specific indigenous cultures like the Inca. It gave me a strong pan-Americas fellow feeling. But, even more grandly, it made me think big picture about, well, the rise and fall of civilizations - and how much human innovation can be lost at the end of a gun, germs, and steel.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Emily Oster&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2301469212?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Expecting Better&lt;/a> AKA how to be pregnant. Ho ho jk jk. I kid. Sort of. TL;DR: Be an economist about it! Oster uses statistical know-how, combined with the decision making framework we learn in Economics School, to talk about the inherent risk and uncertainty of pregnancy. I referred to it constantly, and referred all my friends of childbearing age to it as well. My citation rate on this book was &lt;em>very&lt;/em> high.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Most pleasurable in the moment
&lt;div id="most-pleasurable-in-the-moment" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#most-pleasurable-in-the-moment" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Then there were the books that, while they didn&amp;rsquo;t indelibly tattoo my DNA, were just a whole lotta fun to read. These were the page-turners, the stay-up-late-ers.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Paul Kalanithi&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2435116120?book_show_action=false&amp;amp;from_review_page=1" target="_blank">When Breath Becomes Air&lt;/a>. Weird to call this a page-turner, but this intelligent, sparkling memoir of a 30something neurosurgeon with late stage lung cancer &lt;em>is&lt;/em>. You will probably sob at the end. But you will also feel spiritually refreshed.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Gore Vidal&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2398347521?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Julian&lt;/a>. A dark, funny drama about early Christianity vs. late stage Rome, as embodied in the idealistic, handsome and short-lived Emperor Julian. Snarky and amusing, and also deeply tactile. You live and breathe the 4th century AD! (And yes, I put Anno Domine instead of Common Era as a nod to the book&amp;rsquo;s sad conclusion - Christian Dark Ages win, after all.)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Angie Thomas&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2441712217?book_show_action=false&amp;amp;from_review_page=1" target="_blank">The Hate U Give&lt;/a>. Great YA, moving and powerful and refreshing. The protagonist is so sensible and lovable, you just wish you had a friend like this when you were a teen.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Dexter Palmer&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2251960301?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Version Control&lt;/a>. After such a disappointing slew of mediocre mainstream SF in the last couple years, FINALLY a good one! This time travel story was layered and delightful. I sometimes cite it for its insightful acumen regarding dating apps (their incentive is &lt;em>not&lt;/em> to get you into a relationship, but to keep you on the app - and they do this by leveraging a false sense of abundance and decision fatigue!).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>And, my unplanned-for &amp;ldquo;tech culture is so crazy!&amp;rdquo; books, Emily Chang&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2585538781?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Brotopia&lt;/a> (aaah sexism) and Dan Lyons&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2601467477?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Disrupted&lt;/a> (aaah Millennial chaos).&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Most hated
&lt;div id="most-hated" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#most-hated" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>There were a few books that I found pretty lame - &lt;a href="https://www.goodreads.com/review/show/2373140235?book_show_action=false&amp;amp;from_review_page=1" target="_blank">that Shashi Kapoor biography&lt;/a> was a huge missed opportunity, and &lt;a href="https://www.goodreads.com/review/show/2272462698?book_show_action=false&amp;amp;from_review_page=1" target="_blank">the Sex Criminals series&lt;/a> went off the rails. But the absolute worst book I read, by far, was &lt;a href="https://www.goodreads.com/review/show/2605099887?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Light Years&lt;/a>. My goodness. That was a book club book - and, I mean, I love that book club makes me read outside of my comfort zone - but this was so far out of my comfort zone as to be in hell. There were so many layers of horribleness - from the racist caricatures, the &amp;ldquo;male gaze&amp;rdquo; POV and mansplainy sexism, the moral vacuousness of the main characters, and the pretentiousness of the writing style - OOOOOOF.&lt;/p>
&lt;h2 class="relative group">Sad little dharma nook
&lt;div id="sad-little-dharma-nook" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#sad-little-dharma-nook" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;m &lt;em>supposed&lt;/em> to always have a dharma book in circulation, after a promise to myself made many years ago that I would keep the dharma fires alive in my heart forever. I&amp;rsquo;ve always interpreted the Three Jewels of Buddhism as a three-legged stool of community (sangha), practice (buddha), and study (dharma). And &lt;code>study&lt;/code> usually meant &lt;code>reading a book&lt;/code> or maybe a &lt;a href="https://www.youtube.com/channel/UCPIyEJzvW7SsbiIrooixjNA" target="_blank">video&lt;/a> or &lt;a href="https://www.buddhistgeeks.org/" target="_blank">podcast&lt;/a>.&lt;/p>
&lt;p>Anyway, this year I kept a low simmer of dharma books, namely via Stephen Batchelor&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2350057506?book_show_action=false&amp;amp;from_review_page=1" target="_blank">After Buddhism&lt;/a> (basically boring) and Robert Wright&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/2494762383?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Why Buddhism is True&lt;/a> (much better). The &lt;em>New Yorker&lt;/em> had a great &lt;a href="https://www.newyorker.com/magazine/2017/08/07/what-meditation-can-do-for-us-and-what-it-cant" target="_blank">essay/review of both books&lt;/a> which both accurately captures the history of American Buddhism, all its inherent tensions (karma?! ladies kill the dharma?!!), and how these two books are situated within and address that tension. It&amp;rsquo;s good! Honestly, it&amp;rsquo;s also probably sufficient.&lt;/p>
&lt;p>Yes, so 2 books and 1 essay. I told you dharma was sad this year.&lt;/p>
&lt;h2 class="relative group">Ursula Le Guin died
&lt;div id="ursula-le-guin-died" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#ursula-le-guin-died" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Also sad, of course, was the loss of Ursula K. Le Guin - AKA my guiding light of speculative fiction. I used to say that Le Guin and Kim Stanley Robinson were battling it out for top SF author spot in my heart, but - after having read more KSR and more Le Guin - I can safely say Le Guin is my number one. She wrote so many masterpieces. Even her short stories are startlingly good (the one about the crazy sex ratio and the crazy society it engenders!). Also her super interesting Taoism stuff!&lt;/p>
&lt;p>Anyway, this year, in memory of her, I re-read &lt;a href="https://www.goodreads.com/review/show/554691431?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Left Hand of Darkness&lt;/a> (which, with &lt;a href="https://www.goodreads.com/review/show/186838556?book_show_action=false&amp;amp;from_review_page=1" target="_blank">The Dispossessed&lt;/a>, I consider one of her magnum opuses and maybe one of the top books of SF ever!?) and also started her YA fantasy series, &lt;a href="https://www.goodreads.com/review/show/2372137205?book_show_action=false&amp;amp;from_review_page=1" target="_blank">The Wizard of Earthsea&lt;/a>.&lt;/p>
&lt;h2 class="relative group">2019 goals
&lt;div id="2019-goals" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#2019-goals" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Well, I really should address a few things.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Better representation&lt;/strong>. English is a big language, written by a bunch of people. I really should make a better effort of reading outside the white dude demographic.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>More science fiction&lt;/strong>. I am always delighted when I find a new SF book to love, but I never make time for it! The &lt;a href="https://en.wikipedia.org/wiki/SF_Masterworks" target="_blank">Gollancz SF masterworks&lt;/a> has been a pretty reliable source of finding incredible, unknown-to-me, underrated-by-everyone masterpieces (&lt;a href="https://www.goodreads.com/review/show/186839174?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Gateway&lt;/a>! &lt;a href="https://www.goodreads.com/review/show/867510354?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Random Acts of Senseless Violence&lt;/a>! &lt;em>&lt;a href="https://www.goodreads.com/review/show/1060724983?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Floating Worlds&lt;/a>!&lt;/em>).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Branching out into historical fiction&lt;/strong>. I got &lt;em>super pumped&lt;/em> after reading &lt;a href="https://www.goodreads.com/review/show/2398347521?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Julian&lt;/a>, and kind of remembered that I used to love history? And the ancients? Big time. I pretty reliably enjoy this stuff, but never, &lt;em>ever&lt;/em> think of it as being &amp;ldquo;my thing&amp;rdquo;. Well! I hereby declare that historical fiction is also my thing! I&amp;rsquo;ve got &lt;a href="https://www.goodreads.com/book/show/13507212-bring-up-the-bodies" target="_blank">Bring Up the Bodies&lt;/a> and &lt;a href="https://www.goodreads.com/book/show/8718.Creation?from_search=true" target="_blank">Creation&lt;/a> somewhere around here, and the author of Floating Worlds, Cecelia Holland, was apparently way big in historical fiction before she wrote her crazy awesome sf?&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>I also discovered &lt;a href="https://www.reddit.com/r/52book/" target="_blank">r/52book&lt;/a> this year, which is just fun preening about &amp;ldquo;oh look how much I read!&amp;rdquo; and a nice place to get pumped/inspired by fellow bookworms. Onwards!&lt;/p></description></item><item><title>Disrupted- My Misadventure in the Start-Up Bubble (2016) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/disrupted_my_misadventure_in_the_startup_bubble/</link><pubDate>Fri, 23 Nov 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/disrupted_my_misadventure_in_the_startup_bubble/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/disrupted_my_misadventure_in_the_startup_bubble/book_jacket_hu4da2f8ef3f3979b9d4c70801ed7c4b1f_39005_330x0_resize_q75_box.jpg 330w,
/posts/disrupted_my_misadventure_in_the_startup_bubble/book_jacket_hu4da2f8ef3f3979b9d4c70801ed7c4b1f_39005_660x0_resize_q75_box.jpg 660w,
/posts/disrupted_my_misadventure_in_the_startup_bubble/book_jacket_hu4da2f8ef3f3979b9d4c70801ed7c4b1f_39005_1024x0_resize_q75_box.jpg 1024w,
/posts/disrupted_my_misadventure_in_the_startup_bubble/book_jacket_hu4da2f8ef3f3979b9d4c70801ed7c4b1f_39005_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/disrupted_my_misadventure_in_the_startup_bubble/book_jacket_hu4da2f8ef3f3979b9d4c70801ed7c4b1f_39005_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Dan Lyons&lt;/li>
&lt;li>Number of pages: 272&lt;/li>
&lt;li>Year published: 2016&lt;/li>
&lt;li>Year read: 2018&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Honestly, I enjoyed this at a 5-star level, but I&amp;rsquo;m trying to avoid hyperbole here.&lt;br/>&lt;br/>A scathing memoir by an old school journalist trying to make it in the brave new world of young tech startups, this book was a hoot. The book is divided into three sections: first, after Lyons is laid off from his old boys Newsweek job, he joins a broey Boston tech startup, HubSpot, and is variously amused and horrified by the Millennial antics there. Second, Lyons explores the economics of what he believes is the second tech bubble (this was my favorite section by far). Third, Lyons describes the Kafkaesque corporate bullying that can happen when one is, ahem, &amp;ldquo;managed out&amp;rdquo;.&lt;br/>&lt;br/>I picked this up after hearing a talk by Lyons which variously impressed and amused me - even if we could argue about whether tech is in a speculatory bubble right now, I think we can all agree that the CULTURE of the tech industry deserves to be popped. I would shelve this book right next to &lt;a href="https://www.goodreads.com/review/show/2585538781?book_show_action=false&amp;from_review_page=1">Brotopia&lt;/a>, in that both offer painfully astute insights into how tech - dominated, for the last ~15 years, by 20something white dudes and fashioning itself a &amp;ldquo;brave new world&amp;rdquo; that &amp;ldquo;disrupts the future&amp;rdquo; - is actually just replicating a lot of old social hierarchies, coupled with fierce agism. Lyons is scorching in this regard: he calls HubSpot&amp;rsquo;s &amp;ldquo;kooky office culture&amp;rdquo; an &amp;ldquo;adult kindergarten&amp;rdquo;, and ceaselessly (and hilariously) mocks the coddling perks for 20somethings. He also notes, horrifyingly, how alienated he is made to feel because he, for example, would rather go home to the wife and kids than do beer bongs with the bros on Friday night. He constantly notes how &amp;ldquo;lily white&amp;rdquo;, &amp;ldquo;pure as driven snow&amp;rdquo; white the whole company is, and the incredible chasms between the values it preaches (radical transparency, e.g.) and what it actually practices (dystopian &amp;ldquo;disappearing&amp;rdquo; of people - e.g. employees who are suddenly fired are rebranded as having &amp;ldquo;graduated for their next awesome adventure&amp;rdquo;). &lt;br/>&lt;br/>That the tech industry has - on average - huge problems with age, sex/gender, and race is well-known. That many companies&amp;rsquo;s cultures are frozen-in-time replications of an extended adolescence - frat houses with a paycheck - is also well-known. For the most part, I enjoyed Lyons&amp;rsquo;s seemingly accurate take-down of what seems to be an extreme case of a general trend. I&amp;rsquo;ve worked at tech startups that had some of these Millennial-minded perks (free beer on tap, e.g.) but also were a little more enlightened (our meeting rooms were all named after prominent women in computer science, aww). I do think this book is worthwhile reading for people that work in these industries, if only to show what NOT to do. Indeed - in a way - the speculation and money washing around the tech industry means that a big spotlight is on their culture; I would LOVE to see similarly scathing satires written about, e.g., academia and the development industry (&lt;a href="https://www.goodreads.com/review/show/745899185?book_show_action=false&amp;from_review_page=1">The Idealist&lt;/a> is the only one I can think of). No industry is immune from madness of one type or another; we are all in our little cultural tribes in that regard, and Lyons - coming from (what I imagine and what he sorta describes) as the cigar-chomping, dick-measuring, self-congratulatory bombastic cynicism of old school journalism - is a big fish out of water in the &amp;ldquo;omg that&amp;rsquo;s awesome!!!&amp;rdquo; culture of Millennial corporatism. &lt;br/>&lt;br/>The second section of the book - when Lyons jokes about trying to awaken some of these young people, via a &lt;a href="https://www.youtube.com/watch?v=X8ulYIVcCeY">Norma Rae-style&lt;/a> inspiring pro-labor speech, to the way many of these &amp;ldquo;perks&amp;rdquo; are just repackaged ways for the company to skimp on its workers (e.g. unlimited PTO being one) - is, in my mind, the best. I LOOOVE labor economics, and I think the tech industry is particularly fascinating in this regard. As I said in my &lt;a href="https://www.goodreads.com/review/show/2585538781?book_show_action=false&amp;from_review_page=1">Brotopia review&lt;/a>, and as &lt;a href="https://scholar.harvard.edu/files/goldin/files/goldin_aeapress_2014_1.pdf">Harvard economist Claudia Goldin says in that one paper&lt;/a>, tech has the potential to dismantle a lot of artificial, arbitrarily-imposed constraints to work - it could be really liberating, from a labor perspective. This opportunity and potential is coupled with huge market forces (which Lyons argues are largely speculative and based on hot air) that, instead, perpetuate old power dynamics and exacerbate inequality. Lyons notes that the second tech bubble&amp;rsquo;s motto is all about &amp;ldquo;exit strategies&amp;rdquo; - grow a company very fast, never turn a profit, do an IPO and cash out. This only benefits founders and VC funders. Young workers are cheaper and easier to exploit: free beer takes the place of pensions; &amp;ldquo;&lt;a href="https://hbr.org/2013/06/tours-of-duty-the-new-employer-employee-compact">tours of duty&lt;/a>&amp;rdquo; take the place of mutual loyalty. &amp;ldquo;Passion&amp;rdquo; and &amp;ldquo;hackathons&amp;rdquo; gain prestige; meaning people see glory in working, essentially, unpaid overtime. &lt;br/>&lt;br/>The third section is Lyons recounting, well, adult bullying - as HubSpot decides it needs to get rid of him, and engages in the frankly cowardly act of &amp;ldquo;managing him out&amp;rdquo;; making his life so miserable that he quits, or hunting for small errors and blowing them out of proportion. This is the least interesting part of the book. I mean, it sucks for Lyons - and toxic workplaces definitely suck - but I don&amp;rsquo;t believe they&amp;rsquo;re special to the tech industry. And so this section just feels like a long personal beef, a rant by Lyons. I felt sorry for him, but was also less interested. There IS, however, an unexpected &amp;ldquo;payoff&amp;rdquo; to this since - once Lyons quits and announces he&amp;rsquo;s planning to write a book about his experiences - HubSpot apparently &lt;a href="https://www.bostonglobe.com/business/2016/03/23/documents-released-hubspot-probe-involving-author-dan-lyons/VZH4CN4kR5p7iyhsKEdwJI/story.html">went from being &amp;ldquo;bozos&amp;rdquo; to being &amp;ldquo;monsters&amp;rdquo; by attempting to hack, extort, and break into (!) Lyon&amp;rsquo;s house (!!)&lt;/a>. I found this INSANE. It seemed like an insanely disproportionate response to what is essentially just a catty, snarky book painting them as annoying at best, incompetent at worst. But not EEEEVIL. So that was a surprising turnaround. But maybe, in the age where &lt;a href="https://nymag.com/intelligencer/2018/11/facebook-hired-republican-consultants-to-seed-stories.html">fake news isn&amp;rsquo;t just Facebook&amp;rsquo;s problem - it&amp;rsquo;s its solution&lt;/a>, this shouldn&amp;rsquo;t be so surprising. &lt;br/>&lt;br/>Anyway, a lot of fun, some horror, many amaze. Recommended.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/26030703" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>The grumpy guide to better conferences</title><link>https://www.angelaambroz.com/posts/the_grumpy_guide_to_better_conferences/</link><pubDate>Sat, 17 Nov 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/the_grumpy_guide_to_better_conferences/</guid><description>&lt;p>There&amp;rsquo;s a wonderful, unique sequence in Kim Stanley Robinson&amp;rsquo;s hard sci-fi book, &lt;a href="https://www.goodreads.com/review/show/1319916875?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Green Mars&lt;/a>, where one of the characters - the mad scientist Sax - attends a conference.&lt;/p>
&lt;p>Sax is portrayed as an intelligent, deeply academic, pro-terraforming geologist/physicist/chemist; in many ways, he&amp;rsquo;s a caricature of the professor &amp;ldquo;on the spectrum&amp;rdquo;, socially awkward and profoundly enmeshed in his work. Green Mars is book 2 in KSR&amp;rsquo;s often-sublime, sometimes-dragging Martian Trilogy. And this digression - essentially a really long chapter about a guy going to a conference - is, oddly, one of the better bits.&lt;/p>
&lt;p>Because the &lt;em>way&lt;/em> Sax attends the conference, the way KSR writes it, is - weirdly, mundanely, inspiringly - fascinating. He flits from lecture to lecture, soaking it all in. And it&amp;rsquo;s a feast. The chapter is a funny little celebration of that Platonic ideal of good conferences: the kinds that get your brain fizzing.&lt;/p>
&lt;p>It&amp;rsquo;s pretty hard to actually go to one of those. But I have been! So far, the best conference I&amp;rsquo;ve been to remains &lt;a href="http://www.openvisconf.com/2016/" target="_blank">OpenVis Conf 2016&lt;/a>. I&amp;rsquo;ve been to a lot of mediocre ones in the meantime, but I will not name names. However, I&amp;rsquo;d like to talk about &lt;strong>how to run a good conference&lt;/strong>. Since I think some small design nudges can really improve things and, as designers always say, spark delight.&lt;/p>
&lt;h2 class="relative group">Put the schedule and WiFi password on the back of the lanyard thingie
&lt;div id="put-the-schedule-and-wifi-password-on-the-back-of-the-lanyard-thingie" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#put-the-schedule-and-wifi-password-on-the-back-of-the-lanyard-thingie" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h4 class="relative group">(also, have a WiFi option&amp;hellip;)
&lt;div id="also-have-a-wifi-option" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#also-have-a-wifi-option" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>Put the damn schedule on the damn stupid thing I&amp;rsquo;m wearing. That piece of plastic is useless, an enormous eco-waste, and it could really serve more than its singular function of &amp;ldquo;Hello, I am a conference attendee, let me into this auditorium&amp;rdquo;.&lt;/p>
&lt;h2 class="relative group">Make a conference Slack
&lt;div id="make-a-conference-slack" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#make-a-conference-slack" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://bocoup.com/" target="_blank">Bocoup&lt;/a> - the web design firm that organizes OpenVis Conf - makes a Slack for their conference each year. This is perfect. You can comment on talks as they&amp;rsquo;re happening. You can post your job opportunities on a &lt;code>#jobs&lt;/code> channel. You can DM the presenters with questions or kudos, or people you met over coffee.&lt;/p>
&lt;h2 class="relative group">Don&amp;rsquo;t only offer men&amp;rsquo;s shirts and treat them as &amp;ldquo;unisex&amp;rdquo;
&lt;div id="dont-only-offer-mens-shirts-and-treat-them-as-unisex" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#dont-only-offer-mens-shirts-and-treat-them-as-unisex" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h4 class="relative group">Instead, buy women&amp;rsquo;s shirts and treat THOSE as &amp;ldquo;unisex&amp;rdquo;
&lt;div id="instead-buy-womens-shirts-and-treat-those-as-unisex" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#instead-buy-womens-shirts-and-treat-those-as-unisex" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>This is one of the most insidious, pet peevey, absurd, annoying things for me. I mean, egregious harassment at tech conferences should be averted by having a Code of Conduct and, you know, EYEBALLS AND A BRAIN. But tech sexism isn&amp;rsquo;t always so over the top. It can also be exhaustingly petty. Wasting money on shirts that essentially fit only men is one of those things.&lt;/p>
&lt;h2 class="relative group">Outlets, outlets, outlets
&lt;div id="outlets-outlets-outlets" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#outlets-outlets-outlets" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Duh.&lt;/p>
&lt;h2 class="relative group">Childcare, childcare, childcare
&lt;div id="childcare-childcare-childcare" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#childcare-childcare-childcare" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h4 class="relative group">And other, better ways to spend a budget
&lt;div id="and-other-better-ways-to-spend-a-budget" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#and-other-better-ways-to-spend-a-budget" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>You&amp;rsquo;re providing free food, endless coffee, maybe hotel shuttles and maybe a social thing with booze. That&amp;rsquo;s nice. But all of this assumes a certain set of behaviors: that I&amp;rsquo;m at that hotel, that I drink coffee and alcohol, that I want to socialize in that way.&lt;/p>
&lt;p>I mean, I usually want to have a glass of orange juice and a nap at the end of a big conference day. I know I&amp;rsquo;m not the only decaf-drinking introvert out there. &lt;a href="http://2017.clojure-conj.org/" target="_blank">Clojure/conj 2017&lt;/a> was pretty nice about this - they had a catered board game bonanza as their social night.&lt;/p>
&lt;p>I&amp;rsquo;d much rather they spend the conference budget on childcare given that, again, women at tech conferences is kind of a thing (a &amp;ldquo;not enough of them&amp;rdquo; thing) and, again, why are we privileging beer &amp;gt; babies in the budget? What&amp;rsquo;s the message here? Let&amp;rsquo;s give parents a leg-up here. Women are often the &amp;ldquo;primary&amp;rdquo; parent, responsible for figuring out baby stuff. Help them out.&lt;/p>
&lt;h2 class="relative group">Instant YouTube
&lt;div id="instant-youtube" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#instant-youtube" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Most conferences are pretty good at this: getting the talks up on YouTube soon-ish after they happen. The &lt;em>best&lt;/em>, by far, was &lt;a href="http://2017.clojure-conj.org/" target="_blank">Clojure/conj 2017&lt;/a>, which achieved miraculous speeds and sometimes had conference talks up &lt;em>the very same day&lt;/em>. This was great because, at a good conference, you&amp;rsquo;ll often have multiple talks you want to see that are unfortunately simultaneous.&lt;/p>
&lt;h2 class="relative group">Ruthlessness towards mic-hogs
&lt;div id="ruthlessness-towards-mic-hogs" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#ruthlessness-towards-mic-hogs" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>There&amp;rsquo;s always one or two abysmal questions at the end; blow-hards wanting to show off, people looking for a platform. The best ways to control for this behavior, I&amp;rsquo;d say, are (a) a pre-Q&amp;amp;A warning that questions should be questions, and (b) training the speaker to deftly and diplomatically cut people off. It can be done!&lt;/p></description></item><item><title>World Without Mind- The Existential Threat of Big Tech (2017) - ⭐</title><link>https://www.angelaambroz.com/posts/world_without_mind_the_existential_threat_of_big_tech/</link><pubDate>Sat, 10 Nov 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/world_without_mind_the_existential_threat_of_big_tech/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/world_without_mind_the_existential_threat_of_big_tech/book_jacket_hu2b6a60cf45051856682e4746fdb77e29_29478_330x0_resize_q75_box.jpg 330w,
/posts/world_without_mind_the_existential_threat_of_big_tech/book_jacket_hu2b6a60cf45051856682e4746fdb77e29_29478_660x0_resize_q75_box.jpg 660w,
/posts/world_without_mind_the_existential_threat_of_big_tech/book_jacket_hu2b6a60cf45051856682e4746fdb77e29_29478_1024x0_resize_q75_box.jpg 1024w,
/posts/world_without_mind_the_existential_threat_of_big_tech/book_jacket_hu2b6a60cf45051856682e4746fdb77e29_29478_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/world_without_mind_the_existential_threat_of_big_tech/book_jacket_hu2b6a60cf45051856682e4746fdb77e29_29478_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Franklin Foer&lt;/li>
&lt;li>Number of pages: 272&lt;/li>
&lt;li>Year published: 2017&lt;/li>
&lt;li>Year read: 2018&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>DNF @ ~30%. More like: threw across room at 30%, after great restraint.&lt;br/>&lt;br/>This was tedious, tiresome and totally lame. It&amp;rsquo;s basically a Great Men history of the tech industry, narrow-minded and completely ignorant of a bunch of contexts (social, economic, historical). The Great Men that I got through were: the Whole Earth Catalog&amp;rsquo;s Stewart Brand, Alan Turing, Ray Kurzweil, Larry Page, Mark Zuckerberg - and I stopped there. There are also some detours into Great Men of History like Descartes and Leibniz. There is a Great Man of Reporting Tech (which I have particular beef about - the best tech reporter these days is Kara Swisher!). &lt;br/>&lt;br/>In between these hagiographies - the only concrete-ish parts of the book - Foer uses vague, hyperbolic language to talk about &amp;ldquo;algorithms&amp;rdquo; and &amp;ldquo;AI&amp;rdquo; and &amp;ldquo;monopolies&amp;rdquo; in a way that feels superficial and like, well, he doesn&amp;rsquo;t have a background in tech or economics. Example: he attributes the tech giants&amp;rsquo; accumulation of monopolistic power as being guided by their &amp;ldquo;theocratic&amp;rdquo;, near-spiritual belief in their own, uh, futury-ness (as prescribed by the Whole Earth Catalog). I guess he&amp;rsquo;s never heard of economies of scale? Or natural monopolies? I&amp;rsquo;m not saying Google &lt;i>is&lt;/i> a natural monopoly, but he kept&amp;hellip; NOT acknowledging this basic idea of econ that I begun to wonder, &amp;ldquo;Wait&amp;hellip; maybe he doesn&amp;rsquo;t know about it.&amp;rdquo; &lt;br/>&lt;br/>In other things he doesn&amp;rsquo;t know about: algorithms! According to Foer, they were invented by Leibniz (?!). They&amp;rsquo;re also, apparently, mystical and indecipherable and certainly not just patterns of deterministic steps following logic (not invented by Leibniz), fed into a machine (also not invented by Leibniz). According to Foer, Turing - as he lay in a field after a good run - had the &amp;ldquo;visionary genius&amp;rdquo; vision of putting algorithms into machines. Not&amp;hellip; Ada Lovelace and Charles Babbage, you know, uh, 100 years before. I mean, this is mind boggling. There&amp;rsquo;s even a bit where Foer recasts Mario Savio&amp;rsquo;s &amp;ldquo;throw yourself onto the gears of the machine&amp;rdquo; speech as a reaction against the oncoming onslaught of computers&amp;rsquo;, uh, computeriness. &lt;br/>&lt;br/>Descriptions of AI - or, I should say, &amp;ldquo;AI&amp;rdquo; - were similarly obfuscated, convoluted, and vague. It seems like whenever Foer didn&amp;rsquo;t know how to explain a technical concept (which was every time he raised a technical concept!), he would just say &amp;ldquo;ALGORITHMS&amp;rdquo; and cue some dramatic music. He conflated neural networks with AI based on cognitive models. He didn&amp;rsquo;t mention, er, HOW algorithms may be problematic. &lt;br/>&lt;br/>ALLLLL THIS would have been vaguely more tolerable if the tone of the book hadn&amp;rsquo;t been so damn ego-heavy and high-falutin&amp;rsquo;. If he hadn&amp;rsquo;t used so many $1 words and philosophical ramblings instead of, well, research evidence and data (of which there is ample to support many of his arguments!).&lt;br/>&lt;br/>Awful. I&amp;rsquo;d recommend Jaron Lanier or Cathy O&amp;rsquo;Neil or Sherry Turkle instead.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/34274961" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Artificial intelligence (1984) -</title><link>https://www.angelaambroz.com/posts/artificial_intelligence/</link><pubDate>Fri, 19 Oct 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/artificial_intelligence/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/artificial_intelligence/book_jacket_hu7b1e252bd4088e390dba72611a91d632_30647_330x0_resize_q75_box.jpg 330w,
/posts/artificial_intelligence/book_jacket_hu7b1e252bd4088e390dba72611a91d632_30647_660x0_resize_q75_box.jpg 660w,
/posts/artificial_intelligence/book_jacket_hu7b1e252bd4088e390dba72611a91d632_30647_1024x0_resize_q75_box.jpg 1024w,
/posts/artificial_intelligence/book_jacket_hu7b1e252bd4088e390dba72611a91d632_30647_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/artificial_intelligence/book_jacket_hu7b1e252bd4088e390dba72611a91d632_30647_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Patrick Henry Winston&lt;/li>
&lt;li>Number of pages: 527&lt;/li>
&lt;li>Year published: 1984&lt;/li>
&lt;li>Year read: 2018&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>DNF at about halfway, and won&amp;rsquo;t review, since - meh - it was fine. I used it during my first Georgia Tech OMSCS course, Knowledge-Based Artificial Intelligence, and that&amp;rsquo;s over now, so&amp;hellip; &amp;#x1f937; &lt;br/>&lt;br/>I mean, I love Winston&amp;rsquo;s MIT AI lectures. They are MIND BLOWINGLY good. &lt;a href="https://www.youtube.com/watch?v=TjZBTDzGeGg&amp;list=PLUl4u3cNGP63gFHB6xb-kVBiQHYe_4hSi">Here they are&lt;/a>. This book is less about &amp;ldquo;optimal&amp;rdquo; AI (in the style of neural nets and machine learning) and more about &amp;ldquo;human-like&amp;rdquo; AI (in the style of mimicking cognitive systems and encoding semantic relationships). Which I find inherently confusing and kind of gratingly dull. ML is more exciting! And seems to make more &amp;ldquo;sense&amp;rdquo; (even if it&amp;rsquo;s less interpretable, often). As such, this book feels like a textbook from history - from a field that has changed quite a lot since it was published.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/3388434" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Keeping it 100 in the terminal</title><link>https://www.angelaambroz.com/posts/keep_it_100_in_the_terminal/</link><pubDate>Mon, 01 Oct 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/keep_it_100_in_the_terminal/</guid><description>&lt;p>Hey. Hi. Here&amp;rsquo;s a missed connection:&lt;/p>
&lt;blockquote>
&lt;p>You: Wrote a blog about some super cool bash-based TODO list + journal thing. You kept it all in the Terminal. It was glorious to behold.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Me: Read this in, like, 2014 or something.&lt;/p>
&lt;/blockquote>
&lt;p>Oh, it&amp;rsquo;s hopeless.&lt;/p>
&lt;p>Anyway, I read some blog - SOMEWHERE - by some guy (I think it was a guy? statistically, it was probably a guy) who had this very cool setup of keeping an ongoing journal and TODO list all from the Terminal and all in Vim. He (?) was all about writing writing writing, as a hack to keep his productivity up. And I am all about that too.&lt;/p>
&lt;p>So I finally implemented something like it! It took me on a nice journey through bash/zsh, and, oh, how I love my zsh. Here are some previous adventures in it:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.angelaambroz.com/blog/posts/2018/Apr/25/such_zsh_merit/" target="_blank">In which I scrap bash and set up zsh&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.angelaambroz.com/blog/posts/2018/May/23/yet_another_dotfiles_repo/" target="_blank">In which I set up my dotfiles, like a boss&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 class="relative group">Specs
&lt;div id="specs" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#specs" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>OK, for this tutorial/thing I did, I wanted:&lt;/p>
&lt;ul>
&lt;li>A todo list thingie from the Terminal.&lt;/li>
&lt;li>A journal thingie from the Terminal.&lt;/li>
&lt;li>A way to kill Evernote (sorry, Evernote).&lt;/li>
&lt;/ul>
&lt;h3 class="relative group">&lt;code>todo.txt&lt;/code>
&lt;div id="todotxt" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#todotxt" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>First step was easy. Someone already built a CLI TODO list manager, and that person is &lt;a href="https://ginatrapani.org/" target="_blank">Gina Trapani&lt;/a> (thank you, Gina), who made &lt;a href="http://todotxt.org/" target="_blank">todo.txt&lt;/a>.&lt;/p>
&lt;p>It&amp;rsquo;s super easy to install - just &lt;code>brew install todo-txt&lt;/code> on a Mac. Then you need to configure your &lt;code>~/.todo/config&lt;/code> file according to &lt;a href="https://github.com/todotxt/todo.txt-cli/wiki/Troubleshooting" target="_blank">this tip&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">TODO_DIR&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$HOME&lt;/span>&lt;span class="s2">/Dropbox/todo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">TODO_FILE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$TODO_DIR&lt;/span>&lt;span class="s2">/todo.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">DONE_FILE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$TODO_DIR&lt;/span>&lt;span class="s2">/done.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">REPORT_FILE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$TODO_DIR&lt;/span>&lt;span class="s2">/report.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">TMP_FILE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/tmp/todo.tmp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">TODOTXT_DEFAULT_ACTION&lt;/span>&lt;span class="o">=&lt;/span>ls
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You can change the above to whatever, and SUCH is the glory! I have big plans for this, connecting these folders to a bunch of Python scripts for collating, organizing and archiving my TODOs and DONEs.&lt;/p>
&lt;p>Finally, I aliased the actual &lt;code>todo.txt&lt;/code> &lt;a href="https://github.com/todotxt/todo.txt-cli/blob/master/USAGE.md" target="_blank">commands&lt;/a> to spare keystrokes in honor of the great god Productivity. I did this in my &lt;a href="https://github.com/angelaambroz/.dotfiles/blob/master/system/.alias#L17-L20" target="_blank">&lt;code>~/.dotfiles/system/.zshrc&lt;/code>&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">alias&lt;/span> &lt;span class="nv">t&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;todo.sh&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">alias&lt;/span> &lt;span class="nv">ta&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;todo.sh add&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">alias&lt;/span> &lt;span class="nv">td&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;todo.sh do&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">alias&lt;/span> &lt;span class="nv">tls&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;todo.sh ls&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And voila:&lt;/p>
&lt;h3 class="relative group">Journaling from the terminal
&lt;div id="journaling-from-the-terminal" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#journaling-from-the-terminal" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>One of the big things I use Evernote for is keeping an ongoing diary of my workdays - what I&amp;rsquo;m doing, what&amp;rsquo;s confusing, ideas I have. It&amp;rsquo;s where I, for example, paste in charts and SQL queries from the data I am sciencing. But! One thing Evernote does &lt;em>not&lt;/em> do well is - okay, two things. The &lt;em>first&lt;/em> thing it doesn&amp;rsquo;t do well is data privacy. I have no idea where my deeply private data is being stored; what do I know about the Evernote servers? Nuffin. So, I don&amp;rsquo;t like that.&lt;/p>
&lt;p>The &lt;em>second&lt;/em> thing is doesn&amp;rsquo;t do well is, well, this:
$$p(\mathbf{x} | C_{k}) = \frac{(\sum_{i} x_{i})!}{\prod_{i} x_{i}!}\prod_{i} p_{ki}^{x_i} $$&lt;/p>
&lt;p>That is - Markdown+LaTeX math! There&amp;rsquo;s no elegant way to math in Evernote. It&amp;rsquo;s very ugly and horrible. So switching to Markdown is a win.&lt;/p>
&lt;p>Setting up the Terminal-journal (journinal) was easy:&lt;/p>
&lt;ol>
&lt;li>First, I made a directory where I&amp;rsquo;d store my Markdown journals. I aliased it to &lt;code>hawaii&lt;/code> because, that way, it would make me feel happy every time I typed that.&lt;/li>
&lt;li>Second, I wrote the following function into my &lt;a href="https://github.com/angelaambroz/.dotfiles/blob/master/system/.zshrc#L52-L65" target="_blank">&lt;code>~/.dotfiles/system/.zshrc&lt;/code>&lt;/a>:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="k">function&lt;/span> notes&lt;span class="o">()&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">local&lt;/span> &lt;span class="nv">TODAY_NOTES&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>date +%Y-%b-%d_%A&lt;span class="k">)&lt;/span>.md&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="nv">$TODAY_NOTES&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aliased to my notes folder&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> hawaii&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># aliased to my work name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">[[&lt;/span> -z &lt;span class="nv">$1&lt;/span> &lt;span class="o">]]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">SUBDIR&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nv">$WORK&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">SUBDIR&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nv">$1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> vi &lt;span class="nv">$SUBDIR&lt;/span>/&lt;span class="nv">$TODAY_NOTES&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I have subdirectories in &lt;code>hawaii&lt;/code> for &lt;code>work&lt;/code>, &lt;code>personal&lt;/code> and &lt;a href="http://angelaambroz.com/blog/tag/omscs.html" target="_blank">&lt;code>omscs&lt;/code>&lt;/a>, so that way - when I am lamenting life - I can do it directly from the Terminal by simply typing &lt;code>notes personal&lt;/code>. It will either find or auto-create the &lt;code>.md&lt;/code> file with today&amp;rsquo;s date, e.g., &lt;code>2018-10-01_Monday.md&lt;/code>, and enter Vim for me:&lt;/p>
&lt;h3 class="relative group">&lt;code>RPROMPT&lt;/code>
&lt;div id="rprompt" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#rprompt" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Okay, so this is a thing I found &lt;a href="https://wynnnetherland.com/journal/contextual-todo-list-counts-in-your-zsh-prompt/" target="_blank">elsewhere&lt;/a>, but the basic idea is: use the right-hand side prompt (&lt;code>RPROMPT&lt;/code>) in your zsh to put stuff like: how many TODOs you have in your code, how many project-specific tasks you have coming up, and the like. It is also cool, so check out &lt;a href="https://wynnnetherland.com/journal/contextual-todo-list-counts-in-your-zsh-prompt/" target="_blank">Wynn&amp;rsquo;s blog&lt;/a>.&lt;/p>
&lt;h3 class="relative group">TODOs on my TODOs
&lt;div id="todos-on-my-todos" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#todos-on-my-todos" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>I have a bunch of Python scripty ideas, e.g.:&lt;/p>
&lt;ul>
&lt;li>To properly destroy Evernote, I want to bulk-migrate all my old notes into the Markdown format.&lt;/li>
&lt;li>I want a weekly archiver that sweeps through my &lt;code>todo.txt&lt;/code> list and my work notes and collates them into one big biweekly update I can send to my boss.&lt;/li>
&lt;li>I am debating the version control on my notes and TODOs. I do not 100% trust a private GitHub repo!!! But maybe it&amp;rsquo;s fine. Debating whether to stick all this stuff in &lt;a href="https://keybase.io/" target="_blank">Keybase&lt;/a> like some sort of Amyericanski spy (sorry, have been watching a lot of &lt;a href="https://www.youtube.com/watch?v=mMJQ5GoLHys" target="_blank">The Americans&lt;/a>).&lt;/li>
&lt;/ul></description></item><item><title>oh no</title><link>https://www.angelaambroz.com/posts/oh_no/</link><pubDate>Sat, 08 Sep 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/oh_no/</guid><description>&lt;p>Semester 1 of Georgia Tech&amp;rsquo;s &lt;a href="http://www.omscs.gatech.edu/" target="_blank">Online Master&amp;rsquo;s in Computer Science&lt;/a>.&lt;/p>
&lt;p>I&amp;rsquo;m taking &lt;a href="https://www.omscs.gatech.edu/cs-7637-knowledge-based-artificial-intelligence-cognitive-systems" target="_blank">CS7637: Knowledge-Based Artificial Intelligence&lt;/a>. My reasons: AI is super awesome; I liked the idea of cognitive science and AI; and one of the instructors - Dr. David Joyner - is very highly spoken of throughout the program for running well-designed courses.&lt;/p>
&lt;p>Prereqs are &amp;ldquo;just some Python&amp;rdquo;. All seems well.&lt;/p>
&lt;blockquote>
&lt;p>Lecture 1: &amp;ldquo;hi here are some blocks. can you order them?&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Me: &amp;ldquo;yes i can&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Lecture 2-8: &amp;ldquo;here are some ideas how computers would do this&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Me: &amp;ldquo;sounds good&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Homework 1: &amp;ldquo;hi isn&amp;rsquo;t AI cool. let&amp;rsquo;s talk freely about that.&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Me: &amp;ldquo;oh man i am going to crush this course - &amp;quot;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Project 1: &amp;ldquo;hi PLEASE BUILD YOUR AI NOW&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Me: &amp;ldquo;wait i&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Project 1: &amp;ldquo;YOU CAN USE PYTHON&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Me: &amp;ldquo;&amp;hellip;&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Project 1: &amp;ldquo;LOOK HERE ARE SOME SIMPLE VISUAL INTELLIGENCE TESTS PLZ SOLVE THESE W YOUR AI AGENT&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Me: &amp;quot;&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Project 1: &amp;ldquo;THEY WILL BE GETTING HARDER&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Numerous forum posts: &amp;ldquo;HI MY AI USES AMAZING COMPUTER VISION AND IS ALREADY SO ADVANCED THAT IT IS TAKING OVER THE LAND AROUND MY CITY IN A GRAY GOO SCENARIO, HOW DO I DEAL WITH THIS? THANK YOU, KIND TEACHERS&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Me: &amp;ldquo;oh no&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;p>So there was a bit of a leap between the lectures and homeworks and the project.&lt;/p>
&lt;p>But all is well now. It&amp;rsquo;s even getting fun (after that first icy shower of &amp;ldquo;oh god what have I signed up for&amp;rdquo;). Though calling the program I&amp;rsquo;m writing &amp;ldquo;AI&amp;rdquo; is very, &lt;em>very&lt;/em> generous&amp;hellip;&lt;/p></description></item><item><title>A Groundhog Day of linear algebras</title><link>https://www.angelaambroz.com/posts/a_groundhog_day_of_linear_algebras/</link><pubDate>Mon, 16 Jul 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/a_groundhog_day_of_linear_algebras/</guid><description>&lt;p>I think linear algebra is much wonderful magic and lore, and I think it&amp;rsquo;s a lifelong commitment. As such, I&amp;rsquo;ve taken linear algebra refreshers and courses many, many times.&lt;/p>
&lt;p>While I haven&amp;rsquo;t found the holy grail of linear algebra courses yet - the course that unlocks linear algebra as a visual and geometric intuition, &lt;em>that is what I seek&lt;/em> - I have found some good ones and some OK ones. And I figured I could review them all today! Why not!&lt;/p>
&lt;hr>
&lt;h2 class="relative group">&lt;a href="https://catalog.american.edu/preview_course_nopop.php?catoid=6&amp;amp;coid=26578" target="_blank">MATH-310: Linear Algebra&lt;/a>, &lt;a href="https://www.american.edu/" target="_blank">American University&lt;/a>
&lt;div id="math-310-linear-algebrahttpscatalogamericanedupreview_course_nopopphpcatoid6coid26578-american-universityhttpswwwamericanedu" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#math-310-linear-algebrahttpscatalogamericanedupreview_course_nopopphpcatoid6coid26578-american-universityhttpswwwamericanedu" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>My first experience of linear algebra. I mean, I took this ~15 years ago (mamma mia). I remember enjoying it. I remember finding it deceptively simple. &amp;ldquo;Oh, it&amp;rsquo;s all just basic math, only on series of numbers. How very plain!&amp;rdquo; Little did I know.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Pros&lt;/th>
&lt;th>Cons&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Very positive experience!&lt;/td>
&lt;td>&lt;a href="http://gph.is/17C3JZF" target="_blank">Well, it was a long time ago.&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Lots of fun!&lt;/td>
&lt;td>Did I really dig into the theory of this stuff?&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>(False) sense of VERY EASY!&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 class="relative group">Summer math camp, &lt;a href="https://www.ox.ac.uk/admissions/graduate/courses/mphil-economics?wssl=1" target="_blank">University of Oxford - MPhil in Economics program&lt;/a>
&lt;div id="summer-math-camp-university-of-oxford---mphil-in-economics-programhttpswwwoxacukadmissionsgraduatecoursesmphil-economicswssl1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#summer-math-camp-university-of-oxford---mphil-in-economics-programhttpswwwoxacukadmissionsgraduatecoursesmphil-economicswssl1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Whence young folk go into econ grad school, thence are they usually exposed to a crash course of linear algebra (again, for many of them). I don&amp;rsquo;t remember learning much here (sorry, Oxford! or maybe you should be apologizing to me, yeesh).&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Pros&lt;/th>
&lt;th>Cons&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Well, it was short.&lt;/td>
&lt;td>Too short.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;/td>
&lt;td>&lt;a href="http://gph.is/17C3JZF" target="_blank">And a long time ago.&lt;/a>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 class="relative group">&lt;a href="https://www.edx.org/course/laff-linear-algebra-foundations-to-frontiers" target="_blank">Linear Algebra - Foundations to Frontiers (LAFF)&lt;/a>, &lt;a href="https://www.edx.org/school/utaustinx" target="_blank">UT-Austin, via EdX&lt;/a>
&lt;div id="linear-algebra---foundations-to-frontiers-laffhttpswwwedxorgcourselaff-linear-algebra-foundations-to-frontiers-ut-austin-via-edxhttpswwwedxorgschoolutaustinx" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#linear-algebra---foundations-to-frontiers-laffhttpswwwedxorgcourselaff-linear-algebra-foundations-to-frontiers-ut-austin-via-edxhttpswwwedxorgschoolutaustinx" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This linear algebra course, offered freely via the EdX platform, is &lt;a href="https://www.class-central.com/course/edx-linear-algebra-foundations-to-frontiers-1337" target="_blank">very highly rated&lt;/a> and I was excited to take it. It also promised a visual-first teaching style, a &amp;ldquo;different&amp;rdquo; way of teaching linalg, and a very engaged set of professors and instructors.&lt;/p>
&lt;p>Unfortunately, me and this course! We just didn&amp;rsquo;t connect! I churned my way through about 1/3 of it before giving up.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Pros&lt;/th>
&lt;th>Cons&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Proof-heavy.&lt;/td>
&lt;td>Proof-heavy.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Free!&lt;/td>
&lt;td>Forced use of their idiosyncratic/esoteric linear algebra software (instead of just &lt;code>numpy&lt;/code> or something!)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Self-paced&lt;/td>
&lt;td>Mostly theoretical. Most exercises/homework are proofs.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Always (?) available&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 class="relative group">&lt;a href="https://www.khanacademy.org/math/linear-algebra" target="_blank">Linear algebra&lt;/a>, &lt;a href="https://www.khanacademy.org/" target="_blank">Khan Academy&lt;/a>
&lt;div id="linear-algebrahttpswwwkhanacademyorgmathlinear-algebra-khan-academyhttpswwwkhanacademyorg" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#linear-algebrahttpswwwkhanacademyorgmathlinear-algebra-khan-academyhttpswwwkhanacademyorg" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Honestly, Khan Academy has consistently blown my mind on such diverse topics as:&lt;/p>
&lt;ul>
&lt;li>Natural selection (MY MIND WAS BLOWN)&lt;/li>
&lt;li>Information theory (SO BLOWN)&lt;/li>
&lt;li>Renaissance Italian art (OMG AND I THOUGHT I KNEW ALL ABOUT THIS)&lt;/li>
&lt;/ul>
&lt;p>A lot of this has to do with Sal Khan&amp;rsquo;s incredible clarity of thought, &lt;a href="https://www.khanacademy.org/youcanlearnanything" target="_blank">inherent pedagogical optimism/growth mindset&lt;/a>, and his special talent of breaking everything down into a simple, understandable building block - and then using those blocks to build, ahem, TRULY INCREDIBLE TOWERS OF THOUGHT.&lt;/p>
&lt;p>I love love love Khan Academy, it&amp;rsquo;s one of my monthly charitable donations, and I recommend it to everyone for everything.&lt;/p>
&lt;p>Anyway, so the linear algebra track! I switched to this from LAFF (above) and have slowly cobbled my way through it over the past N years (yes, years). Like LAFF, it is relatively heavy on proofs. Unlike LAFF, it starts with getting some of the basics of linear algebra calculations out of the way - there are a good number of exercises in the early sections which help you get some sense of doing basic calculations with vectors and matrices.&lt;/p>
&lt;p>That said - it quickly takes off and becomes a lecture series of Sal Khan working through various proofs. This has pros and cons: a main pro is that Sal Khan is one of the few people I&amp;rsquo;ve found that can walk you through a proof in a way that feels instantly clear and simple. He&amp;rsquo;s just good at it. And I&amp;rsquo;ve had many &amp;ldquo;ah ha&amp;rdquo; moments. The main con is sticking power: after Sal walks me through a proof, I&amp;rsquo;m like &amp;ldquo;ah ha, okay&amp;hellip; now what?&amp;rdquo; There&amp;rsquo;s no immediate application. There&amp;rsquo;s rarely even a real world example of how/why this is amazing or useful. And thus I find it basically impossible to retain the takeaway.&lt;/p>
&lt;p>Whereas that&amp;rsquo;s what I want! I want to develop an intuitive understanding of linear algebra such that I can &amp;ldquo;see&amp;rdquo; the changes visually. See &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/03/jacobian_stuff/" target="_blank">my post on Jacobian transformations&lt;/a> for an example of when it has &amp;ldquo;clicked&amp;rdquo;.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Pros&lt;/th>
&lt;th>Cons&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Proof-heavy.&lt;/td>
&lt;td>(Eventually) proof-heavy.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Free!&lt;/td>
&lt;td>Exercises dwindle after an initial burst - there aren&amp;rsquo;t many other ways to stay engaged.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Self-paced&lt;/td>
&lt;td>Limited real-world examples/applications to work through or think about.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Always available&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Sal Khan is a great teacher. Maybe the best!&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>More use of visual/geometric examples.&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 class="relative group">&lt;a href="https://classroom.udacity.com/courses/ud953" target="_blank">Linear algebra refresher&lt;/a>, &lt;a href="https://www.udacity.com/" target="_blank">Udacity&lt;/a> and &lt;a href="http://www.omscs.gatech.edu/" target="_blank">Georgia Tech&lt;/a>
&lt;div id="linear-algebra-refresherhttpsclassroomudacitycomcoursesud953-udacityhttpswwwudacitycom-and-georgia-techhttpwwwomscsgatechedu" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#linear-algebra-refresherhttpsclassroomudacitycomcoursesud953-udacityhttpswwwudacitycom-and-georgia-techhttpwwwomscsgatechedu" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This one is freshest in my mind (since I&amp;rsquo;ve been working through it over the last couple days), and it&amp;rsquo;s also my first semi-official introduction to the &lt;a href="http://omscs.gatech.edu/" target="_blank">OMSCS&lt;/a>. I was a little irritated with this course, though, since the idea was &lt;em>great&lt;/em> but the execution was uggghhh.&lt;/p>
&lt;p>The idea was: let&amp;rsquo;s refresh/learn the basic ideas of linear algebra by building our own linear algebra library! In any language we like! Sounds great.&lt;/p>
&lt;p>The execution though, was really, &lt;em>really&lt;/em> painful. The instructor would quickly go over some major, deep linear algebra concept - such as determining whether two lines are parallel - and then would introduce the exercise. All the exercises have taken the same form: you are given - via a screenshot (!) of long, arbitrary floats (!!) - some example vectors, and you have to manually peck these long, arbitrary floats into your program (mine was also in Python, like the instructor&amp;rsquo;s) to then solve for whatever. This was only after the instructor mind-numbingly &lt;em>read out all of these numbers&lt;/em> both before &lt;em>and&lt;/em> after you submitted your responses.&lt;/p>
&lt;p>Screenshot:&lt;/p>
&lt;p>What in the Lord. &lt;em>What&lt;/em> in the &lt;em>Lord&lt;/em>?! Who thought this was a good idea? I spent like 40% of this refresher course manually pecking numbers and then, oh, making obvious human errors because manually transcribing numbers is an incredible waste of my time. Why didn&amp;rsquo;t they just print the numbers as text?! Then I could copy-paste? Also, why did the instructor need to literally read out &amp;ldquo;four point zero four six ex plus two point eight three six why equals one point two one&amp;rdquo; both before &lt;em>and&lt;/em> after, when he reads out the answers?! What an incredible waste of time and awful UX/UI. For shame!&lt;/p>
&lt;p>For this reason, I&amp;rsquo;m only about halfway through this, and I&amp;rsquo;ll choke the rest down (it&amp;rsquo;s meant to only take a few hours, and I&amp;rsquo;ve been doing it here and there when I have a minute), but I&amp;rsquo;m really doubtful that I&amp;rsquo;ll have any &amp;ldquo;ah ha&amp;rdquo; moments.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Pros&lt;/th>
&lt;th>Cons&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Choose-your-language build-to-learn pedagogy.&lt;/td>
&lt;td>SEVEN POINT TWO ZERO FOUR EX PLUS THREE POINT ONE EIGHT TWO WHY EQUALS PLEASE USE THREE DECIMAL PLACES OF ACCURACY WHY IN THE WORLD ARE WE PROVIDING EXERCISES BY MANUAL READ-OUT AND HANDWRITTEN SCREENSHOT&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table></description></item><item><title>Ten Arguments For Deleting Your Social Media Accounts Right Now (2018) - ⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/ten_arguments_for_deleting_your_social_media_accounts_right_now/</link><pubDate>Thu, 21 Jun 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/ten_arguments_for_deleting_your_social_media_accounts_right_now/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/ten_arguments_for_deleting_your_social_media_accounts_right_now/book_jacket_hu43d3b50eadbb53efcc6367714e0f3d5e_39442_330x0_resize_q75_box.jpg 330w,
/posts/ten_arguments_for_deleting_your_social_media_accounts_right_now/book_jacket_hu43d3b50eadbb53efcc6367714e0f3d5e_39442_660x0_resize_q75_box.jpg 660w,
/posts/ten_arguments_for_deleting_your_social_media_accounts_right_now/book_jacket_hu43d3b50eadbb53efcc6367714e0f3d5e_39442_1024x0_resize_q75_box.jpg 1024w,
/posts/ten_arguments_for_deleting_your_social_media_accounts_right_now/book_jacket_hu43d3b50eadbb53efcc6367714e0f3d5e_39442_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/ten_arguments_for_deleting_your_social_media_accounts_right_now/book_jacket_hu43d3b50eadbb53efcc6367714e0f3d5e_39442_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Jaron Lanier&lt;/li>
&lt;li>Number of pages: 146&lt;/li>
&lt;li>Year published: 2018&lt;/li>
&lt;li>Year read: 2018&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>A brief, decent book about an obvious thing that many people can&amp;rsquo;t bring themselves to do: stop supporting social media.&lt;br/>&lt;br/>Social media has been likened to the tobacco industry. It&amp;rsquo;s a pervasive problem. We have a bunch of research about how bad it is. The incentive structures are a nightmare. It ruined the 2016 election. It undermines democracy, empathy, actual human connections. It&amp;rsquo;s false and full of lies. It&amp;rsquo;s addictive. It perpetuates our worst instincts; it turns us, as Lanier says, into assholes. And so on. &lt;br/>&lt;br/>Anyway, billions of people use Facebook. What a nightmare! I have no tolerance for the &amp;ldquo;concern troll&amp;rdquo; argument that disadvantaged groups are somehow unable to leave Facebook; I lived in Tanzania for two years and India for one year. In those places, Facebook is now bundled with people&amp;rsquo;s mobile phone plans and offered as a &amp;ldquo;free&amp;rdquo; service. I&amp;rsquo;ve seen an argument (on Twitter): &amp;ldquo;this is the only access to the internet these people have!&amp;rdquo; Oh yes, Facebook offering such succor to the poor and benighted. Give me a break. MPESA gives succor. Facebook sure as hell does not.&lt;br/>&lt;br/>Anyway. I love Jaron Lanier. I saw him speak years ago. Appalled when no one in the audience knew of E.M. Forster&amp;rsquo;s &lt;a href="https://www.goodreads.com/book/show/4711854-the-machine-stops?from_search=true">The Machine Stops&lt;/a>, he strongly recommended it and I read it shortly afterwards. And it &lt;a href="https://www.goodreads.com/review/show/1462841538?book_show_action=false&amp;from_review_page=1">changed my life&lt;/a>. So thanks, Mr. Lanier! I also think his tech skepticism is informed and healthy. And, of course, I&amp;rsquo;m inspired by his weird and quirky interests: his writing is smart, confident, kind-hearted, and wacky. Which is always a balm.&lt;br/>&lt;br/>I wonder how many people have actually deleted their FB accounts&amp;hellip;&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/37830765" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Working remotely or remotely working?</title><link>https://www.angelaambroz.com/posts/working_remotely_or_remotely_working/</link><pubDate>Fri, 15 Jun 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/working_remotely_or_remotely_working/</guid><description>&lt;p>I have a strong interest in labor: that is, the history, sociology, economics and psychology of labor.&lt;/p>
&lt;p>Specifically, I think it&amp;rsquo;s really interesting (and not entirely efficient) the way that we organize our work. We&amp;rsquo;ve inherited things like the 9-to-5 workday and two-day weekends from the Industrial Revolution, Henry Ford, and factory work.&lt;/p>
&lt;p>But not all work is factory work. Of course, there &lt;em>is&lt;/em> some variety in the modern work day - medical residents, for example, have their own (insane!) labor culture - and there does seem to be an increasing movement towards alternative forms of work: remote work, flexible hours, and so forth. But I don&amp;rsquo;t think we&amp;rsquo;re there yet. And I hope to pioneer (with courage!) new, better ways to work. That is, I hope to worry less about &amp;ldquo;performing&amp;rdquo; work and worry more about pursuing actual mastery, actual efficiency, and actual productivity. I&amp;rsquo;m lucky that my employers have generally supported this.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Laboring in grad school vs. laboring at work
&lt;div id="laboring-in-grad-school-vs-laboring-at-work" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#laboring-in-grad-school-vs-laboring-at-work" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I remember, very vividly, my first day of &amp;ldquo;real work&amp;rdquo;: I had just finished my &lt;a href="https://www.ox.ac.uk/admissions/graduate/courses/mphil-economics?wssl=1" target="_blank">economics MPhil at Oxford&lt;/a> and was starting as an &lt;a href="https://www.odi.org/odi-fellowship-scheme" target="_blank">ODI Fellow&lt;/a> in Fiji at the &lt;a href="http://www.pacificwater.org/pages.cfm/water-services/water-demand-management/project-goal-objective-outputs/program-partners/pacific-islands-applied-geoscience-commission-sopac.html" target="_blank">Pacific Islands Applied Geoscience Commission&lt;/a>. At Oxford, it had been left up to me to organize my time and prepare for the final exams. In Fiji (and in nearly every job hence), there was - instead - an expectation to &amp;ldquo;perform work&amp;rdquo; between certain hours in a certain way. Here&amp;rsquo;s the comparison:&lt;/p>
&lt;p>In &lt;strong>Oxford/grad school&lt;/strong>, we had an entire Trinity Term (13 weeks, iirc) to prepare for two 3-hour exams (mine were Development Economics and - &lt;em>surprise&lt;/em> - Labor Economics) and one research thesis. We had no other obligation. No classes, no meetings, nothing. So we all entered our little study caves and only emerged 13 weeks later, pale and with overgrown haircuts.&lt;/p>
&lt;p>Because my academic diligence spilled over into anxiety/panic, I spent the first day of Trinity Term calculating the number of waking hours in those 13 weeks, and dividing them between my exam subjects. I allocated, a priori, a higher proportion to weaker topics. I took zero weekends. Instead, I worked every day using a primitive &lt;a href="https://en.wikipedia.org/wiki/Pomodoro_Technique" target="_blank">pomodoro technique&lt;/a>: 2-hour blocks, followed by N-minute breaks.&lt;/p>
&lt;p>I would do three blocks per day, starting at 8am. I was very strict on the start time (&lt;em>no later than 8am!&lt;/em>), but much more flexible on the break times (sometimes 15 minutes, sometimes an hour long). Hence, my days would sometimes end in the early afternoon (sweet, sweet release), and sometimes drag into the night (oh God).&lt;/p>
&lt;p>That&amp;rsquo;s 6 hours/day, or 42 hours/week, of &lt;em>dedicated&lt;/em>, focused work. Which doesn&amp;rsquo;t sound like a lot.&lt;/p>
&lt;p>But this was, honestly, hell. This was definitely the absolute maximum focused effort I could endure and, by the end of the 13 weeks, I was a wreck. I was also doing things like reading epistemology and aesthetic philosophy &lt;em>for fun&lt;/em>, so I guess I had body-built my brain. But I knew I couldn&amp;rsquo;t maintain this. &amp;ldquo;How do working people do it?&amp;rdquo; I thought. &amp;ldquo;Who can possibly work for 8 hours every day, for years on end?&amp;rdquo;&lt;/p>
&lt;p>At my &lt;strong>first day of my first real job&lt;/strong>, I remember that I woke up very early, got ready very diligently, had butterflies in my stomach, and showed up some 15-20 minutes before start time. (Which, iirc, was 8am in Fiji anyway - work days are shifted earlier in the Pacific.) Naturally, they didn&amp;rsquo;t have something for me to do right then, so my supervisor gave me some internal reports to read. They helped me get my computer set up. Stuff like that. And I remembered thinking: &lt;em>&amp;ldquo;Wait a minute&amp;hellip; am I supposed to just sit here, obediently, and work for the full 8 hours? What about my N-minute breaks?!&amp;rdquo;&lt;/em>&lt;/p>
&lt;p>Of course, I didn&amp;rsquo;t realize that very few people (I&amp;rsquo;m guessing zero people) actually put in 8 hours of dedicated, focused knowledge work for years on end. (Some random study found that people actually do &lt;a href="https://www.inc.com/melanie-curtin/in-an-8-hour-day-the-average-worker-is-productive-for-this-many-hours.html" target="_blank">three hours&lt;/a> of &amp;ldquo;real&amp;rdquo; work per day, and that includes e-mails.) There&amp;rsquo;s all sorts of interruptions: chatting with colleagues, getting lunch, futzing around on the intertoobs, the demon Multitasking and that great False Work God: E-MAIL.&lt;/p>
&lt;p>Reading and writing e-mails was so much easier than bashing my head against econometric methods for determining the returns to education. So much easier than parsing academic articles, working through problem sets, all that. And - best ever - it was &lt;em>commonly seen as &amp;ldquo;working&amp;rdquo;&lt;/em>. Indeed, I would guess that a huge proportion of my pre-tech career was, well, DOING E-MAILS.&lt;/p>
&lt;p>So that was all a bit of a culture shock.&lt;/p>
&lt;h2 class="relative group">Moving into tech: Moving into making
&lt;div id="moving-into-tech-moving-into-making" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#moving-into-tech-moving-into-making" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>My first career was in international development economics. Looking back on those 9 (!) years, I would guesstimate that my aggregate time diary would have been: 40% emails, 30% managing surveys/traveling around, 10% writing reports, 10% doing data analysis, and 10% training people. Actually, remove ~1% from all those chunks for &amp;ldquo;socializing&amp;rdquo;/futzing around, let&amp;rsquo;s be honest.&lt;/p>
&lt;p>Then I moved into tech. A couple things really attracted me to a career in coding: I loved the creativity, the creation of &lt;em>something&lt;/em>, the constant search for automation and efficiency. I loved that, every day, I had something concrete that I could build. I loved the constant puzzles, and the constant learning.&lt;/p>
&lt;p>At the same time, I realized (with some horror) that a career centered around programming brought a new, harsh light to things: either my code ran or it didn&amp;rsquo;t. Either it broke, days later, or it didn&amp;rsquo;t. Either I wrote 10 lines or 1000 lines. Everything was plain as day. No more hiding in well-written e-mails that danced with diplomacy!&lt;/p>
&lt;p>At the same time, given the great clarity with which we could observe each other&amp;rsquo;s actual productivity, there was an accompanying culture of lax-ness on the &amp;ldquo;performance&amp;rdquo; of work. (Yeah, yeah, I know - there are other ways tech people &amp;ldquo;perform&amp;rdquo; their &amp;ldquo;genius&amp;rdquo;/competence, and I can complain about those in another blog post.) There seems to be a general understanding that we&amp;rsquo;re all &lt;strong>intrinsically motivated&lt;/strong>. The office culture is more casual. There&amp;rsquo;s a general tolerance towards remote work and strange hair (I had lavender hair for a while!).&lt;/p>
&lt;p>In a way, this is very, &lt;em>very&lt;/em> freeing. I no longer have to expend so much energy on the performance of work. If I hate rush hour traffic, I can come in later and leave later or not come in at all. If I feel like I&amp;rsquo;m not getting anything done at the office, I can go home and work from there. Of course, a lot of this hangs on the trust of the employer but - well - GitHub commit histories can&amp;rsquo;t lie!&lt;/p>
&lt;h2 class="relative group">How I organize my days
&lt;div id="how-i-organize-my-days" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-i-organize-my-days" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>That said, it&amp;rsquo;s been very hard for me to break certain &amp;ldquo;performing work&amp;rdquo; habits (like feeling guilty about taking breaks). And then there are some &amp;ldquo;performing work&amp;rdquo; habits that are beneficial (like being good at writing professional e-mails!).&lt;/p>
&lt;p>Lately, though, I&amp;rsquo;ve found some very freeing ways to be &lt;em>more&lt;/em> productive and effective, FOR REAL, and less concerned with &amp;ldquo;performing work&amp;rdquo;:&lt;/p>
&lt;h4 class="relative group">Time tracking
&lt;div id="time-tracking" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#time-tracking" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>I use a time tracker to track my actual productive time every day. There are a bunch of different ones out there, but I wanted one that kept my data local (i.e. no sending it to some server). I use &lt;a href="https://qotoqot.com/qbserve/" target="_blank">Qbserve&lt;/a>, which is not free but I &lt;em>highly&lt;/em> recommend.&lt;/p>
&lt;p>You need to customize your time tracking software to understand what&amp;rsquo;s &amp;ldquo;productive&amp;rdquo;, &amp;ldquo;neutral&amp;rdquo; or &amp;ldquo;distracting&amp;rdquo;. Obvious things (like Twitter) are already set as &amp;ldquo;distracting&amp;rdquo;, but I&amp;rsquo;ve also been intentional about correctly labelling stuff that, for example, &lt;em>might&lt;/em> be productive for some people, but is just a compulsive and pointless time-sink for me (like LinkedIn!).&lt;/p>
&lt;p>I&amp;rsquo;ve also waffled &lt;em>a lot&lt;/em> on Slack: I consider Slack an enormous attention-killer and hence productivity-killer. But it&amp;rsquo;s also where I&amp;rsquo;ve had some very useful and informative conversations; for example, working with a colleague to debug some code.&lt;/p>
&lt;p>Anyway, what&amp;rsquo;s nice about time tracking is that it makes you aware of where your time is going - and it makes you think mindfully about &lt;em>how&lt;/em> you want to spend your time. I think learning is an integral part of both my happiness and my productivity, so I&amp;rsquo;ve put all online learning resources (like Udacity, Coursera, Stanford, etc) into the green bucket. Similarly, Qbserve has helped me notice when I&amp;rsquo;ve worked quite hard on one day (which, for me, means 5-6 hours of focused, dedicated work), that I&amp;rsquo;ll likely need to take it easier on the next day (say, 3-4 hours of focused work).&lt;/p>
&lt;h4 class="relative group">Finding my schedule
&lt;div id="finding-my-schedule" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#finding-my-schedule" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>I&amp;rsquo;m very front-loaded: as soon as I wake up, I&amp;rsquo;m starving and full of energy. If it&amp;rsquo;s sunny and 10am, I can basically conquer the world. I progressively lose steam throughout the day until, by the late afternoon/evening, I&amp;rsquo;m very done.&lt;/p>
&lt;p>One thing I noticed recently is that, if I work from home, I &lt;em>strongly prefer&lt;/em> starting at 7:30am and working until, say, 3pm or so. (Again, I try not to worry about the exact number of hours between my first productive moment and my last - I use Qbserve to see how much I&amp;rsquo;ve actually accomplished).&lt;/p>
&lt;p>When I first tried this out, it was a revelation: I got more done, felt more well-rested/energetic, and seemed to have more time! Just because I started earlier and followed my natural (circadian?) rhythm.&lt;/p>
&lt;h4 class="relative group">A focus on outputs
&lt;div id="a-focus-on-outputs" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#a-focus-on-outputs" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>This is the hardest thing for me, and something I&amp;rsquo;m still working on (as is obvious by all my hours-counting above): I have a &lt;em>very&lt;/em> strong impulse to focus on inputs - that is, the number of hours I put in. Obviously, though, what matters is what I end up producing at the end of the day. If it takes me 1 hour to write a good data ETL job, or if it takes me 10 hours, the virtue is in the former (duh).&lt;/p>
&lt;p>So I try to seek automation and get more efficient and be results-focused. And I try, as much as possible, to have concrete (and brief! and measurable!) TODOs at the start of every day. I use &lt;a href="https://evernote.com/" target="_blank">Evernote&lt;/a> for this:&lt;/p>
&lt;p>This TODO list used to be a &lt;em>loooot&lt;/em> longer, dozens of items long. Which was absurd. So now I intentionally try to keep it to &amp;lt;5 items.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Finally, an important note about mortality
&lt;div id="finally-an-important-note-about-mortality" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#finally-an-important-note-about-mortality" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I read a Guardian article in 2008 that was deeply affecting: &lt;a href="https://www.theguardian.com/society/gallery/2008/mar/31/lifebeforedeath" target="_blank">Life Before Death, &lt;em>The Guardian, Mar 31 2008&lt;/em>&lt;/a>. In particular, this quote stayed with me:&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;Gerda couldn’t believe that cancer was cheating her of her hard-earned retirement. “My whole life was nothing but work, work, work,” she told me.&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>This struck me. A lot of people, on their death beds, have only one regret: working too much, at the expense of other things in their lives. I think this is important even if you love your work (as I do!). We don&amp;rsquo;t have infinite tomorrows, neither do our loved ones, and so it&amp;rsquo;s good to be intentional about working &lt;em>enough&lt;/em> and working &lt;em>well&lt;/em>, but not sacrificing everything for it.&lt;/p></description></item><item><title>Introducing triestin</title><link>https://www.angelaambroz.com/posts/introducing_triestin/</link><pubDate>Wed, 30 May 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/introducing_triestin/</guid><description>&lt;p>I did it! I&amp;rsquo;m done! I finished &lt;a href="https://cs50.harvard.edu/" target="_blank">CS50&lt;/a>. Now is the time for a feeling of accomplishment, mixed with sadness. GOODBYE, CS50! Will I ever MOOC as well as I MOOCed with thee? Who knows.&lt;/p>
&lt;p>Anyway. The final project! Yes! I had a GREAT IDEA for my final project:&lt;/p>
&lt;blockquote>
&lt;p>To write a programming language in not-English, and thus examine whether not-English languages can convey new programming concepts.&lt;/p>
&lt;/blockquote>
&lt;p>Ambitious! I had originally wanted to do it all in C as well: I envisioned fields of &lt;code>malloc()&lt;/code> and &lt;code>free()&lt;/code>. But, well, I gave up on that and ended up writing and compiling it to Python. EASY MODE. My middle names.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">tldr: Here it is!
&lt;div id="tldr-here-it-is" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#tldr-here-it-is" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/introducing_triestin/trst_hu2678d03542d0eae3e70bea8908d237be_135445_330x0_resize_box_1.gif 330w,
/posts/introducing_triestin/trst_hu2678d03542d0eae3e70bea8908d237be_135445_660x0_resize_box_1.gif 660w,
/posts/introducing_triestin/trst_hu2678d03542d0eae3e70bea8908d237be_135445_1024x0_resize_box_1.gif 1024w,
/posts/introducing_triestin/trst_hu2678d03542d0eae3e70bea8908d237be_135445_1320x0_resize_box_1.gif 2x"
src="https://www.angelaambroz.com/posts/introducing_triestin/trst_hu2678d03542d0eae3e70bea8908d237be_135445_660x0_resize_box_1.gif"
alt="a gif of a programming language"
/>
&lt;/figure>
&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Writing a programming language: In theory
&lt;div id="writing-a-programming-language-in-theory" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#writing-a-programming-language-in-theory" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Let&amp;rsquo;s say you open up &lt;a href="https://repl.it/" target="_blank">https://repl.it/&lt;/a>, choose a language, write some stuff, and then run it. What, exactly, happens when you run &lt;code>run&lt;/code>?&lt;/p>
&lt;p>Well: Under the hood, a programming language is doing three things. This is apparently what all languages do. Let&amp;rsquo;s go step by step.&lt;/p>
&lt;h3 class="relative group">Inputting the string
&lt;div id="inputting-the-string" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#inputting-the-string" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>The zero-th step for any language is accepting a text (string) input. You type in &lt;code>print(&amp;quot;hello world&amp;quot;)&lt;/code> in Python. That string - &lt;code>'print(&amp;quot;hello world&amp;quot;)'&lt;/code> - gets accepted by the language. Okay!&lt;/p>
&lt;h3 class="relative group">Lexing/Tokenizing
&lt;div id="lexingtokenizing" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#lexingtokenizing" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>The next step is tokenizing. This is where some heavy &lt;a href="https://regexr.com/" target="_blank">regex&lt;/a> comes in. You (the language) need to look at the string and figure out how to split it into its constituent parts. The split is determined by the idiosyncracies of your &lt;strong>syntax&lt;/strong>. That is, how are strings of letters interpreted - is &lt;code>print&lt;/code> the name of a variable? A number? &lt;a href="http://knowyourmeme.com/memes/is-this-a-pigeon" target="_blank">Is it a pigeon&lt;/a>? Or is it a &lt;strong>keyword&lt;/strong> (that is, a special/reserved word in the syntax)? Spoiler, but &lt;code>print&lt;/code> is a keyword in Python - it calls the &lt;code>print()&lt;/code> function.&lt;/p>
&lt;p>Actually, this is easier with an example. Let&amp;rsquo;s print &lt;em>&amp;ldquo;hello world&amp;rdquo;&lt;/em> in a few different languages (including &lt;code>triestin&lt;/code>!) and write out the resulting tokenization:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Python&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">print&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Tokens: &amp;#34;print&amp;#34;, &amp;#34;(&amp;#34;, &amp;#34;&amp;#34;hello world&amp;#34;&amp;#34;, &amp;#34;)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># C&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">printf&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Tokens: &amp;#34;printf&amp;#34;, &amp;#34;(&amp;#34;, &amp;#34;&amp;#34;hello world&amp;#34;&amp;#34;, &amp;#34;)&amp;#34;, &amp;#34;;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Clojure&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">(&lt;/span>println &lt;span class="s2">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Tokens: &amp;#34;(&amp;#34;, &amp;#34;println&amp;#34;, &amp;#34;&amp;#34;hello world&amp;#34;&amp;#34;, &amp;#34;)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Triestin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">dimmi hello world fin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Tokens: &amp;#34;dimmi&amp;#34;, &amp;#34;hello world&amp;#34;, &amp;#34;fin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;small>(Note to self: Add syntax highlighting for &lt;code>triestin&lt;/code>&amp;hellip;)&lt;/small>&lt;/p>
&lt;p>In &lt;code>triestin&lt;/code>, I &lt;a href="https://github.com/angelaambroz/triestin/blob/master/triestin/lexer.py" target="_blank">saved my tokens&lt;/a> as &lt;code>namedtuples&lt;/code> with a type (&lt;code>tipo&lt;/code>) and a value (&lt;code>val&lt;/code>). For example, from the above, if &lt;code>triestin&lt;/code> found a &lt;code>dimmi&lt;/code> token, it would save it as &lt;code>Token(tipo=&amp;quot;print&amp;quot;, val=&amp;quot;dimmi&amp;quot;)&lt;/code>.&lt;/p>
&lt;p>One &lt;strong>important thing about tokenizing&lt;/strong> is that it&amp;rsquo;s &lt;strong>ordered&lt;/strong> - that is, we need to look through our input string and make sure we don&amp;rsquo;t, e.g., mistake &lt;code>dimmi&lt;/code> for a variable name. There&amp;rsquo;s precedence, and keywords come first!&lt;/p>
&lt;h3 class="relative group">Parsing
&lt;div id="parsing" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#parsing" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Okay, so now we have a bunch of tokens. Or rather: we have an ordered string of tokens, like so:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># input string: dimmi hello world fin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Token&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tipo&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;print&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">val&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;dimmi&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">Token&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tipo&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;identifier&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">val&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;hello world&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">Token&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tipo&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;fin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">val&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;fin&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now what? Now we need to parse them. Parsing means taking those tokens and composing them into an &lt;strong>abstract syntax tree (AST)&lt;/strong>. That is, we need to translate the input string -&amp;gt; tokens -&amp;gt; something semantic and meaningful which conveys what the user wanted to do. For &lt;code>dimmi hello world fin&lt;/code>, we know that &lt;code>fin&lt;/code> is the delimiter and anything after &lt;code>dimmi&lt;/code> is what we&amp;rsquo;ll want to print. Parsing those tokens is easy then. In pseudocode:&lt;/p>
&lt;ol>
&lt;li>From the stack of tokens, pop off the first one.&lt;/li>
&lt;li>Inspect it. Is it &lt;code>dimmi&lt;/code>?&lt;/li>
&lt;li>If so, keep popping off more tokens until you get to &lt;code>fin&lt;/code>.&lt;/li>
&lt;li>Put all those tokens into a string.&lt;/li>
&lt;li>Save all that into a &lt;code>PrintNode&lt;/code> in your abstract syntax tree. The &lt;code>val&lt;/code> (value) of the &lt;code>PrintNode&lt;/code> will just be the string to be printed.&lt;/li>
&lt;/ol>
&lt;p>Easy!&lt;/p>
&lt;p>The harder stuff is in parsing function definitions and function calls. Our language needs to be able to support an arbitrary number of nested arguments and functions. This can be accomplished by:&lt;/p>
&lt;ol>
&lt;li>From the stack of tokens, pop off the first one.&lt;/li>
&lt;li>Inspect - is it a function definition (&lt;code>ecco&lt;/code>)?&lt;/li>
&lt;li>If so, parse a function definition. This includes parsing its arguments, its body, and - if the body has a function call in it - looping back, parsing &lt;em>that&lt;/em> call&amp;rsquo;s arguments and expressions, and so on. You can keep recursively parsing through a function of functions, etc, to an arbitrary depth of levels.&lt;/li>
&lt;/ol>
&lt;p>You can see all this in &lt;a href="https://github.com/angelaambroz/triestin/blob/master/triestin/parser.py" target="_blank">parser.py&lt;/a>.&lt;/p>
&lt;p>In the end, though, you&amp;rsquo;ll have an AST with, one hopes, the input code correctly represented as a tree of calls, variables, functions, and so on.&lt;/p>
&lt;h3 class="relative group">Compiling
&lt;div id="compiling" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#compiling" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>And now! What do we do with our AST? This is somewhat tricky, but mostly easy (parsing is the hardest part, I reckon): we crawl through our tree and, node by node, convert each node to the target language - i.e. the language we want to compile to. I chose Python because it&amp;rsquo;s easy! And &lt;code>triestin&lt;/code> made the same assumptions as Python (i.e. it was dynamically typed, it didn&amp;rsquo;t handle memory explicitly, etc.).&lt;/p>
&lt;p>So how do we compile? Well, we just untangle the node into its constituent parts and then create an output string in Python! With a &lt;code>PrintNode&lt;/code> (which parsed &lt;code>dimmi&lt;/code>, remember), it&amp;rsquo;s super simple: &lt;code>&amp;quot;print('{}')&amp;quot;.format(node.val)&lt;/code>! Just pipe that output string to Python and Python will do what it&amp;rsquo;s told! Voila.&lt;/p>
&lt;p>One note: like with parsing, compiling is recursive - that is, you have no idea how many nodes you have, and how nested they are. So you gotta keep generating and generating, node by node, until you run out of nodes and have gone down every &amp;ldquo;branch&amp;rdquo; of the tree.&lt;/p>
&lt;p>Here&amp;rsquo;s &lt;a href="https://github.com/angelaambroz/triestin/blob/master/triestin/compiler.py" target="_blank">compiler.py&lt;/a>.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Writing a programming language: In practice
&lt;div id="writing-a-programming-language-in-practice" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#writing-a-programming-language-in-practice" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Yeah, right. That all sounds fine. But how was the process?&lt;/p>
&lt;p>Well - my process was OK. I took it fairly easy and it took me about six weeks of dabble-here, dabble-there.&lt;/p>
&lt;p>I started with &lt;a href="http://www.buildyourownlisp.com/" target="_blank">Build Your Own Lisp&lt;/a>, which is a (free) book to learn how to write a Lisp-like language in C. I got through 11 (!) of its 16 chapters, but eventually called it quits, since it had just gotten away from me. I had no idea what I was doing, I was confused, I was copy-pecking way too much, and bah. So that was a big dead end.&lt;/p>
&lt;p>Thankfully, I found &lt;a href="https://www.destroyallsoftware.com/" target="_blank">Destroy All Software&lt;/a>&amp;rsquo;s great videos - specifically, &lt;a href="https://www.destroyallsoftware.com/screencasts/catalog/a-compiler-from-scratch" target="_blank">A compiler from scratch&lt;/a>. In that video, DAS writes a language in Ruby that compiles to JavaScript. I know JavaScript and Ruby is similar enough to Python that I could translate it pretty easily. &lt;code>triestin&lt;/code> is &lt;em>heavily&lt;/em> based on this video.&lt;/p>
&lt;p>All the other speed bumps were small potatoes - figuring out how to do math &lt;em>seemed&lt;/em> inordinately hard, until I sat down and employed the Lazy Angela Way - i.e. I just directly fed anything that seemed mathy straight to Python and let Python handle it.&lt;/p>
&lt;p>I actually ended up learning a lot of handy Python while building this: breaking everything out into modules, learning about when to use and when &lt;em>not&lt;/em> to use a &lt;code>Class&lt;/code>, working with &lt;code>namedtuples&lt;/code>. It was great!&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Linguistic side-eye: A detour into &lt;code>anzi&lt;/code> and &lt;code>è&lt;/code>
&lt;div id="linguistic-side-eye-a-detour-into-anzi-and-%C3%A8" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#linguistic-side-eye-a-detour-into-anzi-and-%C3%A8" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h3 class="relative group">&lt;code>anzi&lt;/code>
&lt;div id="anzi" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#anzi" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>The big &lt;em>point&lt;/em> of &lt;code>triestin&lt;/code>, the big hypothesis, is that &lt;strong>because most (all?) programming languages are written in English, we may be limiting the programmatic concepts that get out there&lt;/strong>. That is, it&amp;rsquo;s kind of like the &lt;a href="https://en.wikipedia.org/wiki/Linguistic_relativity" target="_blank">Sapir-Whorf hypothesis&lt;/a> - tldr, that language affects our thoughts - only for software design. This is beyond the obvious implication that English-speaking programmers have a sociocultural, and &lt;em>not technical&lt;/em>, advantage over everyone else just because every damn language is written in their own damn language!&lt;/p>
&lt;p>I was super into Sapir-Whorf back in grad school, but I&amp;rsquo;m less enamored with it now (though I still highly recommend &lt;a href="https://www.amazon.com/Language-Thought-Action-S-I-Hayakawa/dp/0156482401" target="_blank">this book&lt;/a>). I decided to try to think through some words which are difficult to translate into English. German is famous for having words like this, but, interestingly, I think most languages have words without exact counterparts (languages are not one completely overlapping Venn diagram!). For example:&lt;/p>
&lt;ul>
&lt;li>&lt;code>doch&lt;/code> in German, which I find impossible to understand totally, but kinda means &amp;ldquo;the opposite of what you just said&amp;rdquo;.&lt;/li>
&lt;li>The &lt;code>-va-&lt;/code> infix in Hindi, e.g. &lt;code>karna&lt;/code> (करना, &amp;ldquo;to do&amp;rdquo;) vs. &lt;code>karvana&lt;/code> (करवाना, &amp;ldquo;to have done&amp;rdquo;), which converts verbs from active to passive.&lt;/li>
&lt;li>Swahili&amp;rsquo;s precisely logical &amp;ldquo;compounding words&amp;rdquo;: &lt;code>nimekupenda&lt;/code> (&amp;ldquo;I have loved you&amp;rdquo;), which breaks out into &lt;code>ni-&lt;/code> (&amp;ldquo;I&amp;rdquo;), &lt;code>-me-&lt;/code> (&amp;ldquo;have&amp;rdquo;), &lt;code>-ku-&lt;/code> (&amp;ldquo;you&amp;rdquo;) and &lt;code>-penda&lt;/code> (&amp;ldquo;love&amp;rdquo;). Man, Swahili logic is &lt;em>so cool&lt;/em>. (Also, infixes.)&lt;/li>
&lt;/ul>
&lt;p>All of these could be turned into interesting programmatic concepts! I think programming languages are more than pure logic (though they are mostly that) - there are language design choices that, in turn, determine the design of products built in that language. And our software design world is, for now, monolingual!&lt;/p>
&lt;p>So I thought I&amp;rsquo;d try to implement a not-English concept. Namely, I thought I&amp;rsquo;d try to implement a programmatic concept for &lt;code>anzi&lt;/code>, an Italian word that kinda means &amp;ldquo;the opposite of what was just said&amp;rdquo; (so, I think like &lt;code>doch&lt;/code> in German?) but can also mean &amp;ldquo;rather&amp;rdquo; or &amp;ldquo;instead of&amp;rdquo; or &amp;ldquo;actually&amp;rdquo;. I feel like, meta-semantically, &lt;code>anzi&lt;/code> means &amp;ldquo;HARK, CONTEXT!&amp;rdquo; But how to use a contexty word like &lt;code>anzi&lt;/code> in a programming language? It would have to know context, i.e. remember what had just been said.&lt;/p>
&lt;p>In pseudocode, I decided &lt;code>anzi&lt;/code> would be a &lt;strong>&amp;ldquo;reassignment operator&amp;rdquo;&lt;/strong>. That is, after assigning a variable, &lt;code>x&lt;/code>, to some value, &lt;code>y&lt;/code>, if the user said &lt;code>anzi z fin&lt;/code>, then &lt;code>x&lt;/code> would be reassigned to &lt;code>z&lt;/code>!&lt;/p>
&lt;p>But this meant, &lt;em>ugggghhh&lt;/em>, that I would have to figure out how to have state in my language. Ugghghhhh. STTAAAAATTTEEE. Noooooo. Ohhhhhh nooooo.&lt;/p>
&lt;p>OK, I complained a lot. It seemed hard. I ended up hacking an awful solution. Here are the steps:&lt;/p>
&lt;p>First, in &lt;a href="https://github.com/angelaambroz/triestin/blob/master/triestin/parser.py" target="_blank">parser.py&lt;/a>, let&amp;rsquo;s make an &lt;code>AnziNode&lt;/code> and parse it:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">parse_anzi&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> `anzi` is kind of like &amp;#39;actually&amp;#39; or &amp;#39;rather&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> it&amp;#39;s kind of like &amp;#34;doch&amp;#34; (German) - it can signify &amp;#34;scratch that&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> programmatic `anzi` will revise whatever assignment you just made (for now)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> e.g.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> x è 1 fin
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> anzi 2 fin
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> x fin
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;gt;&amp;gt; 2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">consume&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;anzi&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">consume_next&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">val&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">consume&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;fin&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">AnziNode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">val&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That is, when someone uses &lt;code>anzi&lt;/code> in &lt;code>triestin&lt;/code>, we&amp;rsquo;ll save the value that they gave us. This is the &lt;code>z&lt;/code> value - the replacement value. Now it needs to be reassigned!&lt;/p>
&lt;p>In &lt;a href="https://github.com/angelaambroz/triestin/blob/master/triestin/compiler.py" target="_blank">compiler.py&lt;/a>, I just fed the &lt;code>AnziNode&lt;/code> through, telling the REPL that it was coming and was special and had a value.&lt;/p>
&lt;p>Then, in the REPL - &lt;a href="https://github.com/angelaambroz/triestin/blob/master/trst" target="_blank">here&lt;/a> - I did this awful hack:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Triestin v0.0.1&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;ctrl+C per uscire&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">local_state&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">State&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="kc">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Python 2 on CLI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_input&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">raw_input&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;triestin&amp;gt; &amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">triestin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">source_code&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">user_input&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">local_state&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_history&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;state&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;exec&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;code&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;state&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;eval&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">eval&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;code&amp;#39;&lt;/span>&lt;span class="p">]))&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">tuple&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">eval&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;code&amp;#39;&lt;/span>&lt;span class="p">])[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">eval&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;code&amp;#39;&lt;/span>&lt;span class="p">]))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;state&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;anzi&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">local_state&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">history&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="s1">&amp;#39;node&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;AssignNode&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prev_node&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">local_state&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">history&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prev_var&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prev_node&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;code&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;=&amp;#39;&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">new_code&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s1"> = &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prev_var&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;code&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_code&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ho jeez. This looks so hideous to me. A local history of whatever has happened in the REPL gets saved and &lt;code>anzi&lt;/code> just looks to the previous command. If it was an assignment node (e.g. &lt;code>x è 1&lt;/code>) then it reassigns whatever &lt;code>1&lt;/code> was to the &lt;code>AnziNode&lt;/code> value. MADNESS.&lt;/p>
&lt;p>&lt;small>(Note to self: let &lt;code>anzi&lt;/code> reassign to previous assignment, without that assignment having happened just before&amp;hellip;)&lt;/small>&lt;/p>
&lt;p>Okay, anyway, good enough.&lt;/p>
&lt;h3 class="relative group">&lt;code>è&lt;/code>
&lt;div id="%C3%A8" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#%C3%A8" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>My next stab for polylingual justice was replacing something considered &lt;em>very&lt;/em> banal and &lt;em>very&lt;/em> basic, the assignment operator (normally &lt;code>=&lt;/code>), to something that &lt;em>should&lt;/em> be equally banal and basic: the Italian word for &amp;ldquo;is&amp;rdquo; - è!&lt;/p>
&lt;p>That way, someone could write &lt;code>x è 1 fin&lt;/code>, which can be read as &amp;ldquo;x è uno&amp;rdquo; - that is, &amp;ldquo;x is one&amp;rdquo;. Easy!&lt;/p>
&lt;p>No, not easy. È has an accent over it, which causes English keyboards to fuss and fritz and generally complain. It also caused Python to fritz and complain: WHAT ENCODING IS THIS?! Because, of course, the computer hegemony is a 26-letter English alphabet one, and &amp;ldquo;è&amp;rdquo; isn&amp;rsquo;t easy to type on my English keyboard, and rant rant rave. It&amp;rsquo;s one character! Just as efficient as &lt;code>=&lt;/code>! But, because of hardware and software design choices, it&amp;rsquo;s a giant pain in the ass to use.&lt;/p>
&lt;p>Anyway, you get my point. Now every time someone has to Google &amp;ldquo;e accent grave&amp;rdquo; to get è so they can copy it over into the &lt;code>triestin&lt;/code> REPL, THEY SHALL KNOW MY RIGHTEOUS INDIGNATION.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Resources
&lt;div id="resources" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#resources" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/angelaambroz/triestin" target="_blank">github.com/angelaambroz/triestin&lt;/a>&lt;/li>
&lt;/ul>
&lt;h4 class="relative group">Computer languages
&lt;div id="computer-languages" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#computer-languages" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;ul>
&lt;li>&lt;a href="http://www.buildyourownlisp.com/contents" target="_blank">&lt;em>Build Your Own Lisp&lt;/em>, Daniel Holden&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.destroyallsoftware.com/screencasts/catalog/a-compiler-from-scratch" target="_blank">&lt;em>A compiler from scratch&lt;/em>, Destroy All Software&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://increment.com/programming-languages/crash-course-in-compilers/" target="_blank">&lt;em>A crash course in compilers&lt;/em>, Increment&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://norvig.com/lispy.html" target="_blank">&lt;em>(How to Write a (Lisp) Interpreter (in Python))&lt;/em>, Peter Norvig&lt;/a>&lt;/li>
&lt;/ul>
&lt;h4 class="relative group">Human languages
&lt;div id="human-languages" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#human-languages" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;ul>
&lt;li>&lt;a href="https://www.amazon.com/Language-Thought-Action-S-I-Hayakawa/dp/0156482401" target="_blank">&lt;em>Language in Thought and Action&lt;/em>, S.I. Hayakawa&lt;/a>&lt;/li>
&lt;li>Anything by John McWhorter! Though &lt;a href="https://www.audible.com/pd/History/The-Story-of-Human-Language-Audiobook/B00DGBECNG" target="_blank">The Story of Human Language (audio-lectures)&lt;/a> and &lt;a href="http://www.slate.com/articles/podcasts/lexicon_valley.html" target="_blank">Lexicon Valley&lt;/a> are excellent.&lt;/li>
&lt;/ul></description></item><item><title>PEMDAS HTML</title><link>https://www.angelaambroz.com/posts/pemdas_html/</link><pubDate>Tue, 29 May 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/pemdas_html/</guid><description>&lt;p>A small thing today: I just delighted myself with the the text editor plugin, Emmet (&lt;a href="https://github.com/emmetio/emmet-atom" target="_blank">Atom&lt;/a>, &lt;a href="https://github.com/sergeche/emmet-sublime" target="_blank">Sublime&lt;/a>). Emmet is useful for HTML/CSS autocompletion. Basically, since HTML is a pain in the butt that always has opening and closing tags (&lt;code>&amp;lt;p&amp;gt;blah blah&amp;lt;/p&amp;gt;&lt;/code>), Emmet uses tab completion to productivity-hack that process: you just type &lt;code>p&lt;/code> and then &lt;code>TAB&lt;/code> and, voila, you get your &lt;code>&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;/code>.&lt;/p>
&lt;p>But that&amp;rsquo;s not the best part. THE BEST PART is that you can tab-complete your way through more complicated HTML trees of classes and IDs. Emmet uses HTML&amp;rsquo;s inherent tree structure (parent, child, and sibling elements) to create an intuitive, order of operations-style process.&lt;/p>
&lt;p>Below, I needed to make another &amp;ldquo;project info card&amp;rdquo; on my &lt;a href="http://www.angelaambroz.com/ds.html" target="_blank">projects page&lt;/a>. Because I&amp;rsquo;m using &lt;a href="https://getbootstrap.com/" target="_blank">Bootstrap&lt;/a>, I needed to pack a bunch of elements together: a &lt;code>&amp;lt;div&amp;gt;&lt;/code>, some links, some paragraphs, spans, blah blah. With Emmet, I did it all in one go. MWAAHHH!&lt;/p>
&lt;p>Voila:&lt;/p>
&lt;p>GLORIOUS.&lt;/p></description></item><item><title>Yet another dotfiles repo</title><link>https://www.angelaambroz.com/posts/yet_another_dotfiles_repo/</link><pubDate>Wed, 23 May 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/yet_another_dotfiles_repo/</guid><description>&lt;p>Today&amp;rsquo;s simple tutorial: getting your dotfiles in order!&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong>: This post was edited and improved in Dec 2020.&lt;/p>
&lt;/blockquote>
&lt;h2 class="relative group">What is dotfiles, precious?
&lt;div id="what-is-dotfiles-precious" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#what-is-dotfiles-precious" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Dotfiles are:&lt;/p>
&lt;ul>
&lt;li>Files that start with &lt;code>.&lt;/code>&lt;/li>
&lt;li>And are technically hidden from you (i.e. they won&amp;rsquo;t show up in Finder or with simple &lt;code>ls&lt;/code>)&lt;/li>
&lt;li>But you can actually just see them if you do &lt;code>ls -a&lt;/code>&lt;/li>
&lt;li>You end up fiddling with them to configure your system when you use the shell a lot&lt;/li>
&lt;/ul>
&lt;p>Probably the most popular dotfile you&amp;rsquo;ll run into is &lt;code>.bash_profile&lt;/code>. This configures your shell (if you&amp;rsquo;re using bash, which - by default - you probably are). But you can have a bunch of other dotfiles - for example, &lt;code>.pgpass&lt;/code> (where your Postgres credentials go), &lt;code>.id_rsa&lt;/code> (where your SSH keys are stored - which, incidentally, sits in a dotfiled directory, &lt;code>.ssh/&lt;/code>), and so on.&lt;/p>
&lt;p>Anyway, I recently made a few dotfiles that I wanted to version control - specifically, my &lt;a href="https://www.angelaambroz.com/blog/posts/2018/Apr/25/such_zsh_merit/" target="_blank">zsh&lt;/a> and &lt;a href="https://www.angelaambroz.com/blog/posts/2018/Apr/25/default_jupyter_startup/" target="_blank">ipython&lt;/a> setups.&lt;/p>
&lt;h2 class="relative group">Making your own dotfiles
&lt;div id="making-your-own-dotfiles" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#making-your-own-dotfiles" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;blockquote>
&lt;p>&lt;strong>You can see my completed dotfiles repo &lt;a href="https://github.com/angelaambroz/.dotfiles" target="_blank">here&lt;/a>.&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>There&amp;rsquo;s a bunch of dotfile guides on the web (see below). My process was Simple Angela&amp;rsquo;s Version. Namely, in my shell, first I made my dotfiles folder and got it ready for &lt;code>git&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir ~/.dotfiles
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/.dotfiles
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir secrets
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;secrets/&amp;#39;&lt;/span> &amp;gt;&amp;gt; .gitignore
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir jupyter
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir system
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;Dotfiles begin...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In other words, from the command line, I made the following directory structure:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">- .dotfiles/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - git/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - jupyter/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - secrets/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - system/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - secrets/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - .gitignore
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And I made sure to &lt;code>.gitignore&lt;/code> anything that shows up in &lt;code>.dotfiles/secrets/&lt;/code>, since that&amp;rsquo;s where I would put any sensitive passwords, URLs, and API keys.&lt;/p>
&lt;p>Now it was just a process of making the relevant dotfiles for each thingie (e.g. my &lt;code>system/&lt;/code> dotfiles would be stuff like my shell configs, &lt;code>git/&lt;/code> would have a global &lt;code>.gitignore&lt;/code>) and make sure that each thingie could find its config. Let&amp;rsquo;s go through it, thingie by thingie:&lt;/p>
&lt;h3 class="relative group">Thingie 1: Jupyter
&lt;div id="thingie-1-jupyter" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#thingie-1-jupyter" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>I&amp;rsquo;ve already written about my default &lt;a href="https://www.angelaambroz.com/blog/posts/2018/Apr/25/default_jupyter_startup/" target="_blank">IPython startup&lt;/a>. But how to get IPython to find it? After all, IPython startup files live in &lt;code> ~/.ipython/profile_default/startup/&lt;/code>. The easiest way is to link the file to your &lt;code>.dotfiles&lt;/code> repo:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ln -s ~/.ipython/profile_default/startup/00-dotfiles.py ~/.dotfiles/jupyter/startup.py
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;h3 class="relative group">Thingie 2: &lt;code>git&lt;/code>
&lt;div id="thingie-2-git" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#thingie-2-git" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>I used &lt;a href="https://github.com/simonwhitaker/gibo" target="_blank">&lt;code>gibo&lt;/code>&lt;/a> to quickly create a giant &lt;code>.global_gitignore&lt;/code> boilerplate to handle all my usual use-cases: Python, PyCharm, Sublime.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/.dotfiles/git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">gibo Python macOS JetBrains SublimeText &amp;gt;&amp;gt; .global_gitignore
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But now how to tell git about it?&lt;/p>
&lt;p>Easy! Git has a global config file, stored in your &lt;code>$HOME&lt;/code> directory, that looks for a global &lt;code>.gitignore&lt;/code> and implements it. (Note that your &lt;code>.gitignore&lt;/code> file can&amp;rsquo;t unfurl &lt;code>$&lt;/code> bashy things, so you have to hard-code the full path to your dotfiles.&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-git" data-lang="git">[core]
editor = /Applications/Sublime\\ Text.app/Contents/SharedSupport/bin/subl -n -w
excludesfile = path/to/home/dir/.dotfiles/git/.global_gitignore
[user]
name = Angela Ambroz
email = angelaambroz@users.noreply.github.com
[alias]
unstage = reset HEAD --
&lt;/code>&lt;/pre>
&lt;h3 class="relative group">Thingie 3: &lt;code>zsh&lt;/code>
&lt;div id="thingie-3-zsh" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#thingie-3-zsh" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>And finally, the majesty - the cherry on top - the crown jewel: &lt;code>zsh&lt;/code>! How was I going to tell my shell to, well, SHELL RIGHT?! To use this wonderful new dotfiles directory? This was two parts: having &lt;code>.zshrc&lt;/code> (z-shell startup file) loop and source through all the relevant dotfiles, and making sure my shell knew &lt;em>where&lt;/em> to find the z-shell startup file.&lt;/p>
&lt;p>For the latter: I learned about symbolic links (aka, &lt;code>symlinks&lt;/code>) using the &lt;code>ln&lt;/code> utility:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">❯ tldr ln
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ln
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Creates links to files and folders.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Create a symbolic link to a file &lt;span class="o">(&lt;/span>or folder&lt;span class="o">)&lt;/span>:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ln -s path/to/file path/to/symlink
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Overwrite an existing symbolic to point to a different file:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ln -sf path/to/new_file path/to/symlink
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- Create a hard link to a file:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ln path/to/file path/to/hardlink
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(Side note but &lt;a href="https://github.com/tldr-pages/tldr" target="_blank">&lt;code>tldr&lt;/code>&lt;/a> - i.e. plain English &lt;code>man&lt;/code> pages - is a lifesaver. I doff my hat.)&lt;/p>
&lt;p>Okey dokey:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ln -s ~/.dotfiles/system/.zshrc ~/.zshrc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It&amp;rsquo;s important to include that &lt;code>-s&lt;/code> (symbolic) flag, otherwise you&amp;rsquo;ll just be linking the file once and updates won&amp;rsquo;t be reflected.&lt;/p>
&lt;p>And you can double check that the symlink was truly linked with a quick grep:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">ls -a &lt;span class="p">|&lt;/span> grep &lt;span class="s1">&amp;#39;\-&amp;gt;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For the former (looping through the relevant dotfiles), I just added the following to &lt;code>~/.dotfiles/system/.zshrc&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Load all my secrets&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">SECRETS&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$HOME&lt;/span>&lt;span class="s2">/.dotfiles/secrets&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> file in &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$SECRETS&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>/.*
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">source&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$file&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">done&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Loaded secrets.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Load non-secrets&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">source&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$HOME&lt;/span>&lt;span class="s2">/.dotfiles/system/.alias&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Loaded non-secrets.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Since I broke out my keys et al. into &lt;code>alias&lt;/code>es and &lt;code>EXPORT&lt;/code>s in the &lt;code>secrets/&lt;/code> dir, and my less interesting, non-secret &lt;code>alias&lt;/code>es in &lt;code>system/.alias&lt;/code>.&lt;/p>
&lt;p>And that&amp;rsquo;s it!&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://media.giphy.com/media/yE17oiGeqzING/giphy.gif" alt="marcello" />
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Resources
&lt;div id="resources" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#resources" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://medium.com/@webprolific/getting-started-with-dotfiles-43c3602fd789" target="_blank">Medium/@webprolific - Getting started with dotfiles&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://thoughtbot.com/upcase/videos/intro-to-dotfiles" target="_blank">Thoughtbot - Intro to dotfiles&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://dotfiles.github.io/" target="_blank">Github does dotfiles&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Look, I made a hat</title><link>https://www.angelaambroz.com/posts/look_i_made_a_hat/</link><pubDate>Sun, 20 May 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/look_i_made_a_hat/</guid><description>&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;Studying the hat. Entering the world of the hat.&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>God, &lt;a href="https://www.youtube.com/watch?v=ducG55pfCMQ" target="_blank">Sondheim&lt;/a>. SONDHEIM! Amazing! Ach.&lt;/p>
&lt;p>Anyway, on this &lt;a href="https://en.wikipedia.org/wiki/Sunday_in_the_Park_with_George" target="_blank">Sunday in the apartment with Angela&lt;/a>, let&amp;rsquo;s celebrate a &amp;ldquo;hat&amp;rdquo; three (lazy) years in the making: &lt;strong>my 2015 &amp;ldquo;second a day&amp;rdquo; video&lt;/strong>! 🎉🎉🎉🎉&lt;/p>
&lt;h2 class="relative group">Background (artist&amp;rsquo;s statement)
&lt;div id="background-artists-statement" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#background-artists-statement" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>On 31 December 2014, I decided I wanted to do one of those &amp;ldquo;second a day&amp;rdquo; projects for the next year. I like the idea of art that plays with time: something that commented on impermanence and something that grew in value over time. Something where &lt;code>time&lt;/code> was a strong component and a &amp;ldquo;second artist&amp;rdquo;.&lt;/p>
&lt;p>A &amp;ldquo;second a day&amp;rdquo; project is great for that: when you think about it, you forget most days you live. By capturing a single second, you get insight - you preserve a moment. It&amp;rsquo;s also great because, by condensing time, you see the slow-moving changes: hair growing, weight gain or loss, all that.&lt;/p>
&lt;p>Anyway, in December 2014, I was living in Dar es Salaam, Tanzania, but I knew I would be moving somewhere else after sometime in 2015. I knew 2015 would be a busy year full of change: a lively year!&lt;/p>
&lt;h2 class="relative group">Yet more nostalgia: Python
&lt;div id="yet-more-nostalgia-python" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#yet-more-nostalgia-python" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This project was also my first Python project. While it was painless to &lt;em>film&lt;/em> a second a day, I realized it would be painful to &lt;em>edit&lt;/em> all those multi-second videos into one, ~6 minute thing. And so I had that &lt;em>one fateful thought&lt;/em>:&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;Wait, is this something I could use Python for?&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>The answer to that question is usually &lt;strong>yes&lt;/strong>. Specifically, I used &lt;a href="https://www.udacity.com/course/programming-foundations-with-python--ud036" target="_blank">Udacity&amp;rsquo;s Programming Foundations with Python&lt;/a> and found &lt;a href="https://zulko.github.io/moviepy/" target="_blank">MoviePy&lt;/a> and - I was off to the races!&lt;/p>
&lt;p>Three years later, I can safely say my Python code was &amp;ndash; yeeechhhh, AWFUL. But hey &lt;code>¯\_(ツ)_/¯&lt;/code> whatever. Girl&amp;rsquo;s gotta learn somehow.&lt;/p>
&lt;h2 class="relative group">That was years ago&amp;hellip;
&lt;div id="that-was-years-ago" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#that-was-years-ago" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>What would Sondheim, Mandy, and Bernadette have to say about all this nostalgia?&lt;/p>
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/4MCVsMSsIJU" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen>&lt;/iframe>
&lt;p>MOOOOOVEEEE OOOOOOOOONNNNNNNNNNNN&lt;/p></description></item><item><title>Social media is cigarettes</title><link>https://www.angelaambroz.com/posts/social_media_is_cigarettes/</link><pubDate>Fri, 18 May 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/social_media_is_cigarettes/</guid><description>&lt;blockquote>
&lt;p>The GDPR represents a huge legal shift, which is arriving simultaneously with a technical shift (mass adoption of ad-blockers, which Doc Searls calls &lt;a href="https://blogs.harvard.edu/doc/2015/09/28/beyond-ad-blocking-the-biggest-boycott-in-human-history/" target="_blank">the biggest boycott in human history&lt;/a>) and an emerging normative shift in the form of the &lt;a href="https://twitter.com/search?q=%23deletefacebook&amp;amp;src=typd" target="_blank">#DeleteFacebook movement&lt;/a>, &lt;strong>which is on its way to treating your friends&amp;rsquo; insistence that you use Facebook to communicate with them as akin to insisting that you inhale their second-hand smoke as a condition of socializing with them.&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>&amp;ndash; &lt;a href="https://boingboing.net/2018/05/01/higher-yield-efforts.html" target="_blank">&lt;em>The GDPR might actually create an &amp;ldquo;attention economy&amp;rdquo;&lt;/em>&lt;/a>, Cory Doctorow via BoingBoing (&lt;strong>emphasis&lt;/strong> mine)&lt;/p>
&lt;p>I&amp;rsquo;ve &lt;a href="http://angelaambroz.com/blog/posts/2018/Feb/05/full_stack_python_my_first_flask_app/" target="_blank">talked about social media before&lt;/a>. My feelings about it have been on a steady decline since 2011 or so. They&amp;rsquo;re pretty rock bottom now. What&amp;rsquo;s the benefit? Why should I waste my time to perpetuate knee-jerk outrage and be &lt;a href="https://en.wikipedia.org/wiki/Surveillance_capitalism" target="_blank">advertised to and tracked&lt;/a>? I like Cory&amp;rsquo;s point: social media is the cigarettes of the modern era - culturally pervasive, seemingly innocuous in small doses but with &lt;a href="https://stallman.org/facebook.html" target="_blank">growing evidence&lt;/a> of addiction and harm.&lt;/p>
&lt;p>Actually, some backstory:&lt;/p>
&lt;p>In 2004, I joined &lt;code>thefacebook&lt;/code>. In 2007, I discovered the digital civil liberties crowd (mostly via &lt;a href="https://craphound.com/" target="_blank">Cory Doctorow&amp;rsquo;s Creative Commons-licensed sci-fi&lt;/a>). In 2010, I started thinking I should delete Facebook. I was noticing that I would &amp;ldquo;perform my life&amp;rdquo; for status updates and likes, that I would lurk on the profiles of ex-classmates and compare myself to them (and mostly feel bad, or feel a sick gloating feeling), that I was spending &lt;em>way&lt;/em> more time on it than I wanted to. In 2013, I joined Twitter for work, had fun - and then &lt;a href="https://en.wikipedia.org/wiki/Gamergate_controversy" target="_blank">Gamergate&lt;/a> happened.&lt;/p>
&lt;p>In 2014, I deleted Facebook - prompting one hour of panic, followed by &lt;em>years&lt;/em> of contentment. I&amp;rsquo;m still on Twitter, since I feel like I need to &amp;ldquo;market&amp;rdquo; my &amp;ldquo;tech person&amp;rdquo; &amp;ldquo;brand&amp;rdquo;, but I&amp;rsquo;ve been implementing all sorts of &amp;ldquo;tying Odysseus to the mast&amp;rdquo; stuff to limit its &lt;a href="https://www.youtube.com/watch?v=kxkrdLI6e6M" target="_blank">dark patterns&lt;/a>, and generally treating it like a dangerous animal that I&amp;rsquo;m locked in a cage with. (Uh, the cage is my mind? Or societal norms?)&lt;/p>
&lt;h2 class="relative group">More ranting
&lt;div id="more-ranting" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#more-ranting" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>One narrative is that social media is on its way to derailing our democracy - thanks, 2016 US election. The addictive potential and the automation of propaganda has led to the rise of &amp;ldquo;alternative facts&amp;rdquo; and multiple realities; the power of leveraging social networks to reiterate people&amp;rsquo;s inwardness and cocoon everyone from different realities, only exposing them to the extremist worst of the &amp;ldquo;Other&amp;rdquo; (e.g. &lt;em>&amp;ldquo;You wouldn&amp;rsquo;t believe what this girl brought to her Kent State graduation!&amp;rdquo;&lt;/em> - saved you a click: someone was obnoxious somewhere). The monetization of outrage! It&amp;rsquo;s the stuff of dystopias.&lt;/p>
&lt;p>I&amp;rsquo;m actually equally horrified by two things: (1) the global pervasiveness of the social media addiction, and (2) the way my most social media-active friends seem less themselves and more homogenized mouthpieces for whatever the latest outrage meme is.&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://media.giphy.com/media/ZIDzDGwj22tAA/giphy.gif" alt="body snatched!" />
&lt;/figure>
&lt;/p>
&lt;p>On the latter: After the 2016 election, especially, I started to notice that some of my friends - especially the most outraged and social media-active - would tell me stuff that felt&amp;hellip; packaged? Like, they didn&amp;rsquo;t feel like themselves to me anymore, not like they did 5 or 10 years ago: their personalities were getting subsumed by whatever Facebook/Twitter/IG meme was flowing around that day, &lt;a href="https://en.wikipedia.org/wiki/Invasion_of_the_Body_Snatchers_%281978_film%29" target="_blank">&lt;em>Invasion of the Body Snatchers&lt;/em>&lt;/a> style. Like, since when do you know what Hamilton said in the Federalist Papers? Wait, and why are you mad about X, but not about equally-repellant Y? Wait, where are you getting your news?!&lt;/p>
&lt;p>Then I remembered. Back in the early 2010s, I often thought that Facebook was &lt;em>&amp;ldquo;where I get my news. How will I know what&amp;rsquo;s going on in the world?&amp;rdquo;&lt;/em> I think a lot of people think that way. But that is, ahem, VERY BAD.&lt;/p>
&lt;p>Like, they&amp;rsquo;ve become the amalgamation of their Social Media Outrage Diet - they don&amp;rsquo;t have their &lt;em>own&lt;/em> worries, their &lt;em>own&lt;/em> thoughts. They don&amp;rsquo;t pursue &lt;em>their&lt;/em> causes; they pursue the causes that an algorithm designed to maximize their engagement (for advertising dollars) has fed them. That&amp;rsquo;s what it feels like. I know, I know, I&amp;rsquo;m on my high horse, I&amp;rsquo;m reading minds, I&amp;rsquo;m just as manipulated by cultural fads as everyone, blah blah. This is just a feeling I have.&lt;/p>
&lt;p>None of my friends have quit social media. My feelings are generally pessimistic; that I&amp;rsquo;m screaming into the void about it. Oh well.&lt;/p>
&lt;h2 class="relative group">Tutorial: Defang Twitter
&lt;div id="tutorial-defang-twitter" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#tutorial-defang-twitter" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>So, anyway. Imagine, if you will: Thunderdome. Me and Twitter are in the cage together, circling each other. How can I win!?&lt;/p>
&lt;p>The best way to defang Twitter (and any social media), I think, is to defang all its &amp;ldquo;viral&amp;rdquo; properties. I don&amp;rsquo;t need to see the latest tweet that got 100k retweets and 200k likes by someone I don&amp;rsquo;t know or haven&amp;rsquo;t explicitly followed. It probably went viral because it scratched some reptile-brain itch in my in-group; some outrage about &amp;ldquo;the Other&amp;rdquo; (e.g. the Trump voter, the coastal elite) being horrible, or some pithy witticism. I can live without pithy witticisms! There is more to my life than that. I want more to my life! Okay, enough ranting.&lt;/p>
&lt;h3 class="relative group">How to turn off &lt;strong>retweets&lt;/strong>
&lt;div id="how-to-turn-off-retweets" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-to-turn-off-retweets" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Twitter obviously doesn&amp;rsquo;t want you to do this. They &lt;em>want&lt;/em> you to be &amp;ldquo;engaged&amp;rdquo; (i.e. to be on the site), addicted. Thus &lt;em>not&lt;/em> seeing viral stuff goes against engagement. Anyway, first: turning off retweets. You can do this manually, profile by profile, for each person you follow. This is intentionally onerous.&lt;/p>
&lt;p>Or, you can use &lt;a href="https://twitter.com/b0rk/status/924823854157127686?lang=en" target="_blank">Julia Evans&amp;rsquo;s&lt;/a> little webapp, &lt;a href="https://turn-off-retweets.glitch.me/" target="_blank">https://turn-off-retweets.glitch.me/&lt;/a>, and it&amp;rsquo;ll automate through your list of follows and turn off retweets. Twitter gets MUCH MORE QUIET. Good!&lt;/p>
&lt;h3 class="relative group">How to turn off &lt;code>so-and-so liked&lt;/code>
&lt;div id="how-to-turn-off-so-and-so-liked" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-to-turn-off-so-and-so-liked" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>This is the same deal: you need a bit o&amp;rsquo; JavaScript and HTML tags. I used AdBlockPlus (which already blocks stuff using HTML tags, I&amp;rsquo;m guessing).&lt;/p>
&lt;p>On Chrome, go to:&lt;/p>
&lt;blockquote>
&lt;p>** AdBlockPlus -&amp;gt; Options -&amp;gt; Advanced -&amp;gt; Edit Filters**&lt;/p>
&lt;/blockquote>
&lt;p>And add in:&lt;/p>
&lt;pre tabindex="0">&lt;code>twitter.com##[id^=stream-item-recap_entry-]
twitter.com##.tweet.js-stream-tweet.js-actionable-tweet.js-profile-popup-actionable.dismissible-content.original-tweet.js-original-tweet.tweet-has-context.PocketAdded
&lt;/code>&lt;/pre>&lt;p>Looks kinda Greek to me. Here&amp;rsquo;s what I &lt;em>think&lt;/em> it parses into:&lt;/p>
&lt;ul>
&lt;li>&lt;code>twitter.com##&lt;/code> = Anywhere on Twitter.&lt;/li>
&lt;li>&lt;code>[id^=stream-item-recap_entry-]&lt;/code> = Any HTML element whose &lt;code>id&lt;/code> tag starts with &lt;code>stream-item-recap_entry-&lt;/code>. (I&amp;rsquo;m guessing that caret, &lt;code>^&lt;/code>, is regex?)&lt;/li>
&lt;li>&lt;code>[.tweet.js-stream-tweet.js-actionable-tweet...]&lt;/code> = Any HTML element with any (or all?) of those classes (e.g. &lt;code>.tweet&lt;/code> class).&lt;/li>
&lt;/ul>
&lt;p>You can also do some trial and error with AdBlockPlus&amp;rsquo;s &lt;code>Block Element&lt;/code> button.&lt;/p>
&lt;h2 class="relative group">Further reading
&lt;div id="further-reading" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#further-reading" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.goodreads.com/book/show/28503628-the-attention-merchants" target="_blank">The Attention Merchants&lt;/a>, Tim Wu&lt;/li>
&lt;li>&lt;a href="https://www.goodreads.com/book/show/23258925-the-boy-who-could-change-the-world" target="_blank">The Boy Who Could Change the World&lt;/a>, Aaron Swartz&lt;/li>
&lt;/ul></description></item><item><title>Adventures in crappy architecture, part N</title><link>https://www.angelaambroz.com/posts/adventures_in_crappy_architecture_part_n/</link><pubDate>Thu, 10 May 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/adventures_in_crappy_architecture_part_n/</guid><description>&lt;p>Remember when I said &lt;a href="http://angelaambroz.com/blog/posts/2018/Apr/25/default_jupyter_startup/" target="_blank">how great it was to make a IPython startup file&lt;/a>? Remember those good ego feelings? Yeah, well, I went on vacation and came back and it broke. Goddammit!&lt;/p>
&lt;p>Not only did it stop working, but it stopped working in a weird, dark magic way.&lt;/p>
&lt;h2 class="relative group">Friendly reminder
&lt;div id="friendly-reminder" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#friendly-reminder" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The point of the IPython startup file was that, every time I opened a new &lt;code>ipython&lt;/code> shell or Jupyter notebook, it would automagically (and, in the notebooks, silently) import a bunch of packages I wanted (&lt;code>pandas&lt;/code>, &lt;code>numpy&lt;/code>, etc.) as well as a couple convenience functions (e.g. &lt;code>alert()&lt;/code>). This would spare me having to copy that cell over every time. Hence, it was a minutes-saving, productivity-enhancing tool for near-daily use.&lt;/p>
&lt;p>The problem is that it fails silently in the notebook (it fails noisily in the &lt;code>ipython&lt;/code> shell). So, today, I happily opened a new notebook, double-checked a couple of my expected packages (&lt;code>pd&lt;/code> returned the &lt;code>pandas&lt;/code> object, we are go for launch), and proceeded.&lt;/p>
&lt;p>And then - it broke. Specifically, my notebook complained that it had never heard of &lt;code>alert()&lt;/code>. Huh, what now? It&amp;rsquo;s in the startup file. How can you &lt;em>see&lt;/em> &lt;code>import pandas&lt;/code> but not &lt;code>def alert()&lt;/code>? How does that make any sense?!&lt;/p>
&lt;h2 class="relative group">Fixing it, step 1: &lt;code>ipython&lt;/code> &amp;gt; notebook
&lt;div id="fixing-it-step-1-ipython--notebook" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#fixing-it-step-1-ipython--notebook" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>No error message means no clue, so I had to find the error message. The first place I looked was the Jupyter notebook terminal output:&lt;/p>
&lt;p>Uh, what? &lt;code>[IPKernelApp] WARNING | Unknown error in handling startup files:&lt;/code>&amp;hellip; and nothing?&lt;/p>
&lt;p>This is where &lt;code>ipython&lt;/code> shell is handier:&lt;/p>
&lt;p>Ooooh.&lt;/p>
&lt;blockquote>
&lt;p>Note: That &lt;code>sqlalchemy&lt;/code> import is not the actual error. I had a much weirder error in a package I had written. Namely&amp;hellip;&lt;/p>
&lt;/blockquote>
&lt;h2 class="relative group">Fixing it, step 2: circular imports because I no design software so good
&lt;div id="fixing-it-step-2-circular-imports-because-i-no-design-software-so-good" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#fixing-it-step-2-circular-imports-because-i-no-design-software-so-good" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;ve had something of a dark obsession with design patterns in software for the past ~8 months. Mainly that I don&amp;rsquo;t know any, &lt;em>but I know they&amp;rsquo;re out there&lt;/em>. My colleagues always talk about &amp;ldquo;code smells&amp;rdquo;. WHAT IS A CODE SMELL? Things like that. I watch YouTube videos. &lt;a href="https://www.youtube.com/watch?v=OMPfEXIlTVE&amp;amp;__s=igzvxemrwyh2rgdqkf1t" target="_blank">This one by Sandi Metz was good&lt;/a> - but I just don&amp;rsquo;t write that much Actual Software to have enough practical experience to know this stuff. So I&amp;rsquo;m always hungry to learn more and get better at it.&lt;/p>
&lt;p>One &amp;ldquo;pattern&amp;rdquo; (SCARE QUOTES) I&amp;rsquo;ve decided to adopt is putting global vars at the very tip-top of &lt;a href="https://youtu.be/CCzfQ935CXc?t=5m23s">&lt;s>the American pyramid&lt;/s>&lt;/a> my Python package, i.e. in the &lt;code>__init__.py&lt;/code>. Then I can import them in all sundry modules within the package. So I had something like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># __init__.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">package&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">module1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">.top_module&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Class1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Class2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Global vars&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">STATISTICAL_SIGNIFICANCE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.95&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DEFAULT_POWER&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.9&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But &lt;em>then&lt;/em>, in my &lt;code>module1.py&lt;/code>, I had &lt;em>this&lt;/em>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># module1.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">.&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">STATISTICAL_SIGNIFICANCE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">DEFAULT_POWER&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Oh no. In other words, when I imported my &lt;code>package&lt;/code>, the following would happen:&lt;/p>
&lt;ol>
&lt;li>&lt;code>package&lt;/code> runs &lt;code>__init__.py&lt;/code> to get everything started.&lt;/li>
&lt;li>First thing, it tries to import &lt;code>module1&lt;/code>.&lt;/li>
&lt;li>In &lt;code>module1&lt;/code>, it tries to import &lt;code>STATISTICAL_SIGNIFICANCE&lt;/code> and &lt;code>DEFAULT_POWER&lt;/code>&lt;/li>
&lt;li>Error! It doesn&amp;rsquo;t know what those global vars are! Because they&amp;rsquo;re defined further down the &lt;code>__init__.py&lt;/code>.&lt;/li>
&lt;/ol>
&lt;p>So the &lt;code>__init__.py&lt;/code> initialization fails, and everything fails, and - because I was importing this package about halfway down into my IPython startup file, it failed and only managed to import a few things for my Jupyter notebook. As you can guess, the &lt;code>alert()&lt;/code> function definition was further down my startup file. It never got there.&lt;/p>
&lt;p>So here&amp;rsquo;s my fix!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># __init__.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Global vars&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">STATISTICAL_SIGNIFICANCE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.95&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DEFAULT_POWER&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.9&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">package&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">module1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">.top_module&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Class1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Class2&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Voila! Easy! No more circular stuff. Global vars are defined &lt;em>first thing&lt;/em>. Architecture! Design! SUCCESS!&lt;/p></description></item><item><title>Sourdough (2017) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/sourdough/</link><pubDate>Fri, 27 Apr 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/sourdough/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/sourdough/book_jacket_hu90c8a51c7fba3195832d9f8e09a5087b_35752_330x0_resize_q75_box.jpg 330w,
/posts/sourdough/book_jacket_hu90c8a51c7fba3195832d9f8e09a5087b_35752_660x0_resize_q75_box.jpg 660w,
/posts/sourdough/book_jacket_hu90c8a51c7fba3195832d9f8e09a5087b_35752_1024x0_resize_q75_box.jpg 1024w,
/posts/sourdough/book_jacket_hu90c8a51c7fba3195832d9f8e09a5087b_35752_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/sourdough/book_jacket_hu90c8a51c7fba3195832d9f8e09a5087b_35752_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Robin Sloan&lt;/li>
&lt;li>Number of pages: 259&lt;/li>
&lt;li>Year published: 2017&lt;/li>
&lt;li>Year read: 2018&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>A funny-enough, strange, and well-observed book about Silicon Valley narcissism/tone-deaf transhumanism. It starts VERY strong, but progressively loses steam and ends on a bit of a whimper. &lt;br/>&lt;br/>Robin Sloan has a really sharp eye and satirizes the tech industry super effectively: e.g. the romanticized treatment of being &amp;ldquo;on the spectrum&amp;rdquo;, i.e. mono-focused ~&lt;em>~PASSION~&lt;/em>~, i.e. sleeping at the hipster office so you can churn out code, i.e. a work culture that mostly privileges young men without dependents. The post-human/Singularity types who eat utopian/post-apocalyptic non-food since our evolved digestive system is inefficient and evolution should be ~&lt;em>~DISRUPTED~&lt;/em>~. The fetishization of productivity. Even just the frisson of merging code changes to the /master branch without even making a PR! (MADNESS.)&lt;br/>&lt;br/>The novel - which focuses on a young programmer named Lois, who codes real good but is pretty repulsed by this Bay Area silliness - is a cry for hedonic pleasure, for inefficient and uncontrollable organisms, for YEAST. Which is great. And I was like, &amp;ldquo;oh wow is this a smart, fun book or what, heheh that bay area amirite&amp;rdquo;. And I read on, eagerly anticipating the great, philosophical punchline that I just KNEW had to be coming.&lt;br/>&lt;br/>And I read.&lt;br/>&lt;br/>And I read&amp;hellip;&lt;br/>&lt;br/>And, basically, it never comes? Which is why this was a 4-star instead of 5-star experience. The setup is so superb, our crazy world so accurately observed, that I was SO READY for that philosophical whammy. Hoo well.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/33916024" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Default Jupyter startup</title><link>https://www.angelaambroz.com/posts/default_jupyter_startup/</link><pubDate>Wed, 25 Apr 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/default_jupyter_startup/</guid><description>&lt;p>I have a running mental list of little inefficiencies that annoy me throughout my workdays. The sand, the pebbles, the annoyances of my working life. I try to follow &lt;a href="https://xkcd.com/1205/" target="_blank">this xkcd&lt;/a> in determining if it&amp;rsquo;s worth the time to actually fix them. The basic heuristic is: if it&amp;rsquo;s a &lt;em>small&lt;/em> thing, but I do it every day, it&amp;rsquo;s worth spending a few hours optimizing it.&lt;/p>
&lt;p>Today I tackled one: creating a global config file to auto-import all my favorite modules into any newly-created Jupyter notebook.&lt;/p>
&lt;h2 class="relative group">Background
&lt;div id="background" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#background" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I work a lot with Jupyter notebooks. They&amp;rsquo;re a standard data science tool. What usually happens, though, is I experience &amp;ldquo;Jupyter efficiency drift&amp;rdquo;. I&amp;rsquo;ll spend a chunk of time (several days/weeks) digging into notebooks, and I&amp;rsquo;ll get really good at importing the right modules, setting my &lt;code>matplotlib&lt;/code> up all nice and friendly, and making little &lt;code>IPython&lt;/code> JavaScript helper functions. &lt;em>Then&lt;/em> I&amp;rsquo;ll spend a chunk of time on &lt;em>something else&lt;/em> - like deploying stuff (gettin&amp;rsquo; real good at bash!), or stats stuff (yay Bayes!), or whatever - and I&amp;rsquo;ll have forgotten what my One True Jupyter Notebook setup is.&lt;/p>
&lt;p>My crappy workaround has always been to dig up the last notebook I was working on, and copy the top few cells:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="o">%&lt;/span>&lt;span class="n">load_ext&lt;/span> &lt;span class="n">autoreload&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">%&lt;/span>&lt;span class="n">matplotlib&lt;/span> &lt;span class="n">inline&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pandas&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">pd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">seaborn&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">sns&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">matplotlib&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">mpl&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">IPython.display&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Javascript&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="n">blah&lt;/span> &lt;span class="n">blah&lt;/span> &lt;span class="n">blah&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">mpl&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">rcParams&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;figure.figsize&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">12&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">plt&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">style&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">use&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;bmh&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">alert&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">js&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;alert(&amp;#34;All done!&amp;#34;);&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">display&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Javascript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">js&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">%&lt;/span>&lt;span class="n">autoreload&lt;/span> &lt;span class="mi">2&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The problem was - some notebooks didn&amp;rsquo;t have the entire rigamarole, some were missing my beloved &lt;code>alert()&lt;/code> function, and this was a stupid process. Sometimes I&amp;rsquo;d open a new notebook just to do some small thing, and it seemed like overkill to stay meticulous about copy+pasting that One True First Cell.&lt;/p>
&lt;h2 class="relative group">Solution: &lt;code>~/.ipython/profile_default/startup&lt;/code>
&lt;div id="solution-ipythonprofile_defaultstartup" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#solution-ipythonprofile_defaultstartup" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Because &lt;em>surely&lt;/em> Jupyter must have some top-level, global-environment-style config that can do this for me? I mean, Stata has &lt;code>profile.do&lt;/code>, bash has &lt;code>.bashrc&lt;/code>/&lt;code>.bash_profile&lt;/code>, is this some crazy idea? To paraphrase Kenneth Branagh: &lt;a href="https://youtu.be/jOAHxkUMseY?t=1m34s" target="_blank">no, the world must be dotfiled!&lt;/a>&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://media.giphy.com/media/13RZk2VCJ4vDjy/giphy.gif" alt="people it" />
&lt;/figure>
&lt;/p>
&lt;p>And, indeed, Jupyter - or rather, Jupyter&amp;rsquo;s ur-center, IPython - has &lt;strong>startup files&lt;/strong> (&lt;a href="https://ipython.readthedocs.io/en/stable/interactive/tutorial.html#startup-files" target="_blank">docs&lt;/a>). The basic process:&lt;/p>
&lt;ol>
&lt;li>Go to your default IPython profile&amp;rsquo;s startup folder: &lt;code>cd ~/.ipython/profile_default/startup&lt;/code>&lt;/li>
&lt;li>Make a Python script for what you wanna import: &lt;code>subl 0-the-world-must-be-peopled.py&lt;/code> (Note: You can have multiple scripts, they&amp;rsquo;ll be run in lexicographic order.)&lt;/li>
&lt;li>People that script with your imports! Mine looked like the above &lt;code>import os&lt;/code> etc. stuff. (Note: Cell %magics don&amp;rsquo;t work here, sorry.)&lt;/li>
&lt;/ol>
&lt;p>VOILA! PRODUCTIVITY GAIN.&lt;/p>
&lt;h2 class="relative group">An aside on &lt;code>alert()&lt;/code>
&lt;div id="an-aside-on-alert" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#an-aside-on-alert" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Hey, let&amp;rsquo;s talk about &lt;code>alert()&lt;/code>, by the way.&lt;/p>
&lt;p>I often run stuff in my Jupyter notebooks that takes a while. For example: if I&amp;rsquo;m pulling in lots (and lots) of data from somewhere, and it&amp;rsquo;s just taking forever to load in memory. Or if I&amp;rsquo;m waiting for a PyMC3 MCMC sampling, or a neural net&amp;rsquo;s many epochs.&lt;/p>
&lt;p>In those cases, I want to be alerted when the process completes. Specifically, I want it to pull me back from whatever other thing I&amp;rsquo;ve wandered off to do (e.g. watching &lt;a href="https://www.youtube.com/watch?v=A-yZNMWFqvM" target="_blank">this&lt;/a>). BEHOLD - that&amp;rsquo;s what &lt;code>alert()&lt;/code> is good for:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">IPython.display&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Javascript&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">alert&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">js&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;alert(&amp;#34;All done!&amp;#34;);&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">display&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Javascript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">js&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">some_long_process&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">some_long_process&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">alert&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So &lt;code>alert()&lt;/code> just launches a JavaScript &lt;a href="#" onClick="alert('OH HAI!!!')">alert window&lt;/a> whenever &lt;code>some_long_process()&lt;/code> completes. You may want to manually allow popups in your &lt;code>localhost&lt;/code> via your browser, since (I guess) most modern web browsers block them by default (after much 1990s abuse).&lt;/p>
&lt;p>I mean, you&amp;rsquo;re in the frickin&amp;rsquo; browser anyway, may as well leverage that JavaScript!&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://media.giphy.com/media/l4JyYyhBTUFJ9k6ys/giphy.gif" alt="denzel" />
&lt;/figure>
&lt;/p></description></item><item><title>Such zsh merit</title><link>https://www.angelaambroz.com/posts/such_zsh_merit/</link><pubDate>Wed, 25 Apr 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/such_zsh_merit/</guid><description>&lt;p>I just kicked some serious computer butt today. I would like to share.&lt;/p>
&lt;h2 class="relative group">Original problem
&lt;div id="original-problem" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#original-problem" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I just wanted a way to recursively &lt;code>.gitignore&lt;/code> some &lt;code>.csv&lt;/code> files in my work folders. CSV files, as you know, can get big (BIG). And GitHub doesn&amp;rsquo;t like that; in fact, it was bouncing my &lt;code>git push -u origin master&lt;/code> back - and complaining that I had exceeded the acceptable size of my commit (wow). My previous &lt;code>.gitignore&lt;/code> always only excluded CSV files that were &lt;em>exactly two levels deep&lt;/em>:&lt;/p>
&lt;pre tabindex="0">&lt;code>path/to/top/folder/*/*.csv
&lt;/code>&lt;/pre>&lt;p>But this was no longer true. I had just massively reorganized my folders, and my CSVs were now scattered arbitrary-levels deep in my various project folder trees.&lt;/p>
&lt;p>WHAT TO DO?&lt;/p>
&lt;p>Well, first, this works in your &lt;code>.gitignore&lt;/code>:&lt;/p>
&lt;pre tabindex="0">&lt;code>path/to/top/folder/**/*.csv
&lt;/code>&lt;/pre>&lt;p>Specifically, that double wildcard, &lt;code>**&lt;/code>, says &amp;ldquo;wildcard recursively&amp;rdquo;. That is, &amp;ldquo;search through arbitrary levels of sub-directories&amp;rdquo;. What joy! Which led me into a rabbit hole: &lt;em>wait, can I wildcard recursively in my shell?&lt;/em>&lt;/p>
&lt;h2 class="relative group">Yes, but it&amp;rsquo;s time to move to &lt;code>zsh&lt;/code>
&lt;div id="yes-but-its-time-to-move-to-zsh" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#yes-but-its-time-to-move-to-zsh" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I &lt;em>just&lt;/em> finished a &lt;a href="https://www.goodreads.com/book/show/299534.Learning_the_bash_Shell" target="_blank">very nice book about bash&lt;/a>, and so I didn&amp;rsquo;t want to haul over my well-earned shortcuts and &lt;code>alias&lt;/code>es and all that onto a totally new shell interpreter. Ugh! (Though, to be fair, &lt;a href="https://en.wikipedia.org/wiki/Z_shell" target="_blank">wiki&lt;/a> notes that zsh is a superset of bash.)&lt;/p>
&lt;p>But I saw some StackOverflow post saying that &lt;code>zsh&lt;/code> has the double-glob (&lt;code>**&lt;/code>) built-in, and that - if I wanted it in &lt;code>bash&lt;/code> (my current/the default shell interpreter), I&amp;rsquo;d have to download something or other. So instead of downloading &lt;a href="https://unix.stackexchange.com/questions/49913/recursive-glob" target="_blank">&lt;code>globstar&lt;/code>&lt;/a>, I decided to pull out the GUTS OF THE SHELL ENTIRELY and just install &lt;code>zsh&lt;/code>.&lt;/p>
&lt;p>LET&amp;rsquo;S DO THIS.&lt;/p>
&lt;h3 class="relative group">Installing &lt;code>zsh&lt;/code>
&lt;div id="installing-zsh" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#installing-zsh" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>&lt;code>zsh&lt;/code> is just another shell interpreter, with some nice add-ons and wing-dings that make it a superset of bash. I found &lt;a href="https://github.com/robbyrussell/oh-my-zsh" target="_blank">oh-my-zsh&lt;/a>, which is a &amp;ldquo;community-driven&amp;rdquo; &lt;code>zsh&lt;/code> configuration helper - basically, people have already futzed with &lt;code>zsh&lt;/code> profiles to make things pretty and functional and allow autocomplete, and so on. In general, I think it&amp;rsquo;s wise to follow crowds on tech stuff - where goeth the crowd, there be-eth the StackOverflow answers.&lt;/p>
&lt;p>Anyway, here&amp;rsquo;s me installing &lt;code>zsh&lt;/code> and getting going:&lt;/p>
&lt;pre tabindex="0">&lt;code># OSX has zsh installed, but I saw somewhere that it&amp;#39;s old? so let&amp;#39;s update
brew install zsh
# change default shell from bash to zsh
chsh -s $(which zsh)
&lt;/code>&lt;/pre>&lt;p>Then close and reopen iTerm2! Next was futzing around with the &lt;code>oh-my-zsh&lt;/code> stuff, by enabling &lt;code>oh-my-zsh&lt;/code>, as well as its plugins and themes in my &lt;code>.zshrc&lt;/code>. I also copied over all my various aliases and such from &lt;code>.bashrc&lt;/code> and &lt;code>.bash_profile&lt;/code> to &lt;code>.zshrc&lt;/code>. Everything basically worked fine. (Yes, I&amp;rsquo;ll put my dotfiles on GitHub someday.) For prettiness, I used the &lt;a href="https://github.com/sindresorhus/pure" target="_blank">&lt;code>pure&lt;/code>&lt;/a> prompt theme - which is &lt;em>not&lt;/em> part of &lt;code>oh-my-zsh&lt;/code>, and so needed some overriding. Here&amp;rsquo;s what it looks like, when I&amp;rsquo;ve got my &lt;code>pyenv&lt;/code> environment activated (&lt;code>www_env&lt;/code>), I&amp;rsquo;m on a git &lt;code>master&lt;/code> branch, and I&amp;rsquo;m in the blog folder:&lt;/p>
&lt;h3 class="relative group">Doing the thing I came here to do
&lt;div id="doing-the-thing-i-came-here-to-do" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#doing-the-thing-i-came-here-to-do" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>After spending an hour or so getting &lt;code>zsh&lt;/code> all ported over, all I wanted to do was &lt;strong>remove the giant CSV files from my git history&lt;/strong>. They were several commits behind in my local branch&amp;rsquo;s history, and I was stuck: I needed to roll back to the earliest commit (pre-CSV dump) and remove them (temporarily!) from the directory entirely. I needed to rewrite history. Since I had added the &lt;code>path/to/top/folder/**/*.csv&lt;/code> line to my &lt;code>.gitignore&lt;/code>, whatever changes I made were &lt;em>not&lt;/em> being picked up by git.&lt;/p>
&lt;p>So my plan was:&lt;/p>
&lt;ol>
&lt;li>Banish the CSV files to a temporary &lt;code>data/&lt;/code> folder.&lt;/li>
&lt;li>Roll back to an earlier commit (pre-CSV dump).&lt;/li>
&lt;li>Re-commit everything, now without any CSVs in the git history.&lt;/li>
&lt;li>Push up to &lt;code>origin/master&lt;/code>! 😍&lt;/li>
&lt;/ol>
&lt;p>In &lt;code>zsh&lt;/code>, all that was:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-zsh" data-lang="zsh">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. banish any CSVs in any subdirectory to new top-level data/ folder&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">find ./ -name &lt;span class="s1">&amp;#39;*.csv&amp;#39;&lt;/span> &lt;span class="p">|&lt;/span> xargs -I &lt;span class="s1">&amp;#39;{}&amp;#39;&lt;/span> mv &lt;span class="o">{}&lt;/span> data/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. roll back to earlier commit, pre-CSV troubles&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git reset &lt;span class="o">[&lt;/span>SOME_SHA&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. re-commit everything&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git status
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;OMG CSVS&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Pusshhhhhh!&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push -u origin master
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 5. OH SHIT THE CSVS, WHERE DO I PUT THEM BACK&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>At this point, my good ego feelings quickly disappeared. Since I had moved &lt;em>all&lt;/em> CSVs out of &lt;em>any&lt;/em> directory and plopped them down into &lt;code>data/&lt;/code>, I no longer knew which CSV was associated with which directory (and thus, which project). I was horrified. And my CSVs had cryptic names like &lt;code>A.csv&lt;/code> and &lt;code>eligible.csv&lt;/code>. Huh!?&lt;/p>
&lt;p>Thankfully, I knew that all the CSVs had been used (either created or imported) by some data analysis in Python. So I could just &lt;code>grep&lt;/code> through all my &lt;code>.py&lt;/code> files (recursively, throughout all the directories and sub-directories) to find when and where each CSV file appeared.&lt;/p>
&lt;pre tabindex="0">&lt;code>grep -rI &amp;#39;.csv&amp;#39; ./**/*.py
&lt;/code>&lt;/pre>&lt;p>This showed me that, for example, Python file X in directory Y had been doing stuff with &lt;code>A.csv&lt;/code> - voila! I could return &lt;code>A.csv&lt;/code> to its rightful directory. And now, since all CSVs were &lt;code>.gitignored&lt;/code>, I would never have to worry about this again!&lt;/p></description></item><item><title>CS50 - No more lectures 😭</title><link>https://www.angelaambroz.com/posts/cs50_no_more_lectures_aw_man/</link><pubDate>Wed, 11 Apr 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/cs50_no_more_lectures_aw_man/</guid><description>&lt;p>I was surprised recently to see that I&amp;rsquo;m basically on track to finish CS50 with the end of Harvard&amp;rsquo;s spring 2018 semester. I was surprised because, &lt;a href="http://angelaambroz.com/blog/posts/2018/Mar/20/cs50__data_structures_achievement_unlocked/" target="_blank">back during the C period&lt;/a>, it felt like I was wallowing away weeks &lt;em>and weeks&lt;/em> on some of those problem sets. But, well, they had spring break and a couple off weeks, and so I caught up.&lt;/p>
&lt;p>I finished up the lectures and problem sets this week. The &lt;a href="https://video.cs50.net/2017/fall/lectures/12" target="_blank">final lecture&lt;/a> was actually just a pile o&amp;rsquo; fluff: opening with one of the TAs playing the piano, and lots of pop music montages of &amp;ldquo;oh the places you&amp;rsquo;ll go!&amp;rdquo; stuff. And, funnily, I WAS VERY MOVED. I felt like it was the last day of high school again! SO LONG, CS50, I&amp;rsquo;LL REALLY MISS YINZ! Thanks to Prof. Malan and all the TAs and staff for a wonderful resource, truly!&lt;/p>
&lt;hr>
## Syllabus - in review
&lt;p>The full &lt;a href="https://docs.cs50.net/2018/x/syllabus.html" target="_blank">2018 CS50 syllabus is here&lt;/a>. In retrospect, my favorite topics were, ranked descending:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Memory&lt;/strong>: &lt;em>Huge&lt;/em> demystification of what happens when you computer things.&lt;/li>
&lt;li>&lt;strong>Dynamic programming&lt;/strong>: I want to write a post about this. I had to watch some supplementary YouTubes about this (since I didn&amp;rsquo;t get it with just the lecture), but - once it clicked - OH MAN. Mind blowing. And the applications! Aaah. Just &lt;a href="https://github.com/vivianhylee/seam-carving" target="_blank">&lt;em>look at this&lt;/em>&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Data structures&lt;/strong>: Unexpected elegance, thanks to C&amp;rsquo;s direct memory management, of linked lists and tries and hash tables. Wonderful!&lt;/li>
&lt;li>&lt;strong>HTTP&lt;/strong>: &lt;em>Insufficient&lt;/em> HTTP stuff, though I did discover the fun of &lt;code>traceroute&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Algorithms&lt;/strong>: Meh. This was one lecture. It was okay-fun. But, since we didn&amp;rsquo;t actually implement any algorithms or &amp;ldquo;race&amp;rdquo; any code, it felt remote.&lt;/li>
&lt;/ul>
&lt;hr>
## Problem sets - in review
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Pset&lt;/th>
&lt;th style="text-align:center">Language&lt;/th>
&lt;th style="text-align:center">Joy&lt;/th>
&lt;th style="text-align:center">Est. hours&lt;/th>
&lt;th>Notes&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>0 - Scratch&lt;/td>
&lt;td style="text-align:center">&lt;a href="https://scratch.mit.edu/" target="_blank">Scratch&lt;/a>&lt;/td>
&lt;td style="text-align:center">🙄&lt;/td>
&lt;td style="text-align:center">&amp;lt;1&lt;/td>
&lt;td>Bah.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1 - C&lt;/td>
&lt;td style="text-align:center">C&lt;/td>
&lt;td style="text-align:center">🤔&lt;/td>
&lt;td style="text-align:center">3&lt;/td>
&lt;td>Greedy algorithm, oof.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2 - Crypto&lt;/td>
&lt;td style="text-align:center">C&lt;/td>
&lt;td style="text-align:center">😂&lt;/td>
&lt;td style="text-align:center">2&lt;/td>
&lt;td>&lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/29/clojure__cryptography__maximum_fun/" target="_blank">Already did this once in Clojure.&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3 - Music&lt;/td>
&lt;td style="text-align:center">C&lt;/td>
&lt;td style="text-align:center">😨&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td>HARD. Converting text -&amp;gt; Herz frequencies -&amp;gt; MIDI music. Also, &lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/20/i_heart_waves/" target="_blank">waves&lt;/a>.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4 - Forensics&lt;/td>
&lt;td style="text-align:center">C&lt;/td>
&lt;td style="text-align:center">😨&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td>STILL HARD. Recovering lost JPEGs and bitmaps. Also - I KNOW ALL COMPUTER NOW.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5 - Mispellings&lt;/td>
&lt;td style="text-align:center">C&lt;/td>
&lt;td style="text-align:center">😨&lt;/td>
&lt;td style="text-align:center">5&lt;/td>
&lt;td>Hard. AKA how to build a linked list. Not sucking at &lt;code>malloc()&lt;/code>.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6 - Déjà vu&lt;/td>
&lt;td style="text-align:center">Python&lt;/td>
&lt;td style="text-align:center">🤔&lt;/td>
&lt;td style="text-align:center">4&lt;/td>
&lt;td>Real easy Python + understanding dynamic programming!&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>7 - C$50 Finance&lt;/td>
&lt;td style="text-align:center">Python, SQL&lt;/td>
&lt;td style="text-align:center">😒&lt;/td>
&lt;td style="text-align:center">2&lt;/td>
&lt;td>Flask app + API calling. Fiddly, annoying.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>8 - Mashup&lt;/td>
&lt;td style="text-align:center">JavaScript&lt;/td>
&lt;td style="text-align:center">😒&lt;/td>
&lt;td style="text-align:center">2&lt;/td>
&lt;td>JAVASCRIPT. BAROQUE CATHEDRAL OF CODE.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>TOTAL&lt;/strong>&lt;/td>
&lt;td style="text-align:center">&lt;/td>
&lt;td style="text-align:center">&lt;/td>
&lt;td style="text-align:center">29&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
## Final project
&lt;p>I&amp;rsquo;m about halfway through &lt;a href="http://www.buildyourownlisp.com/contents" target="_blank">Build Your Own Lisp&lt;/a>, which is a lot of fun. I&amp;rsquo;m using it to write a toy language in C called &lt;code>triestin&lt;/code>. It&amp;rsquo;ll be based on the &lt;a href="https://it.wikipedia.org/wiki/Dialetto_triestino" target="_blank">Triestine-Italian dialect&lt;/a>, which is spoken by ~250,000 people. According to &lt;a href="https://www.istat.it/en/labour-and-wages" target="_blank">ISTAT&lt;/a>, the Italian government&amp;rsquo;s statistical agency, 56% of Italians of working age are employed, and 2.6% &lt;em>of those&lt;/em> (I think) are &lt;a href="https://www.west-info.eu/few-people-employed-as-ict-specialists-in-italy/" target="_blank">ICT people&lt;/a>. So that&amp;rsquo;s, hmmm -&lt;/p>
&lt;p>$$250,000 * 0.557 * 0.026 = 3,620$$&lt;/p>
&lt;p>Or about 3,600 people that could potentially understand this language at all! If we whittle things down to people that are interested in compilers, IT&amp;rsquo;S EVEN LOWER. Yay!&lt;/p>
&lt;p>Anyway, I also found &lt;a href="https://www.destroyallsoftware.com/screencasts" target="_blank">Destroy All Software&lt;/a>&amp;rsquo;s wonderful &lt;a href="https://www.destroyallsoftware.com/screencasts/catalog/a-compiler-from-scratch" target="_blank">A compiler from scratch&lt;/a>, which demystified how programming languages are written: it&amp;rsquo;s just tokenizing, parsing, and compiling! Wooooo. Lots of Chomsky stuff too, which I will investigate further.&lt;/p></description></item><item><title>2600 Magazine- The Hacker Quarterly - Winter 2017-2018 (2018) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/2600_magazine_the_hacker_quarterly__winter_20172018/</link><pubDate>Fri, 06 Apr 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/2600_magazine_the_hacker_quarterly__winter_20172018/</guid><description>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): 2600 Magazine&lt;/li>
&lt;li>Number of pages: 238&lt;/li>
&lt;li>Year published: 2018&lt;/li>
&lt;li>Year read: 2018&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>What&amp;rsquo;s super interesting about 2600 (which is a long-running magazine for l33t h4x0rs) is how much it looks and smells and sounds like a punk magazine. Wow, is the aesthetic the same. The posturing ego, the slightly obnoxious tone, the idealism, the rebelliousness. &lt;a href="https://www.youtube.com/watch?v=XAXtqmanVIQ">See one of my fave Portlandia skits.&lt;/a>&lt;br/>&lt;br/>Anyway, this was fun and got me suitably paranoid about WHOIS info (aaagh) and suitably inspired about maybe setting up some sort of antennae to emit destructive interference to my neighbors&amp;rsquo; WiFi signals JUST BECAUSE I CAN. Actually, okay, I don&amp;rsquo;t know if you can do that. Wouldn&amp;rsquo;t that eff up the 2.4GHz spectrum around you for everything? And it&amp;rsquo;s probably illegal (&amp;ldquo;probably illegal&amp;rdquo; being an important slogan of the scene).&lt;br/>&lt;br/>I liked the article about the guy checking a Linux OS&amp;rsquo;s command hashes both upstream (from the OS he forked from, I guess) to downstream (the OS he was the main builder of), since people were spreading rumors that using that command secretly sent secret info stuff to The Man (which is such a a Mr. Robot idea in and of itself). The guy checks the SHA-1s of the command as it was downloaded and as it&amp;rsquo;s deployed are identical - i.e. no one futzed with that command. I didn&amp;rsquo;t know commands even HAD SHA-1s, but that makes sense and WOW THAT&amp;rsquo;S COOL.&lt;br/>&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/37808746" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Two announcements</title><link>https://www.angelaambroz.com/posts/two_announcements/</link><pubDate>Tue, 03 Apr 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/two_announcements/</guid><description>&lt;p>Well, troops, I have good news, and I have good news.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">First good news: SSL
&lt;div id="first-good-news-ssl" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#first-good-news-ssl" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Time to join the modern web! I&amp;rsquo;m happy to announce that &lt;code>angelaambroz.com&lt;/code> is now SSL certified.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Second good news: Georgia Tech&amp;rsquo;s OMSCS
&lt;div id="second-good-news-georgia-techs-omscs" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#second-good-news-georgia-techs-omscs" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;m &lt;em>also&lt;/em> happy - and nervous and excited - to announce that I was &lt;a href="http://www.omscs.gatech.edu/" target="_blank">&lt;strong>accepted into Georgia Tech&amp;rsquo;s Online Master&amp;rsquo;s in Computer Science&lt;/strong>&lt;/a>. Holy moly, Morty!&lt;/p>
&lt;p>This was something I had been thinking about for about four years, and actively working towards for three. My background is in economics, with an okay seasoning of math (e.g. my undergrad minor was math). But I had only ever taken one CS course previously, and it mostly talked about how to fashion a spinning hard drive out of vinyl, wood, and the blood of your clan enemies. Ho ho, kidding, little joke to convey how old I am.&lt;/p>
&lt;p>Anyway, I didn&amp;rsquo;t have much CS background. So, in 2015, while I was working at the &lt;a href="https://www.hks.harvard.edu/" target="_blank">Harvard Kennedy School&lt;/a>, I started taking some CS courses through &lt;a href="https://www.extension.harvard.edu/" target="_blank">Harvard&amp;rsquo;s Extension School&lt;/a>. These courses were hugely helpful. I also started building out some additional CS foundations with free online courses, like &lt;a href="http://angelaambroz.com/blog/posts/2018/Mar/20/cs50__data_structures_achievement_unlocked/" target="_blank">CS50&lt;/a> and &lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/04/journey_to_the_center_of_data_science/" target="_blank">a bunch of other bits and bobs&lt;/a>. But now we&amp;rsquo;ll see - the proof will be in the next few years&amp;rsquo; pudding!&lt;/p>
&lt;h3 class="relative group">Big plans, Morty
&lt;div id="big-plans-morty" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#big-plans-morty" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>I&amp;rsquo;m super pumped about the OMSCS, specifically about pivoting my career more towards artificial intelligence. I&amp;rsquo;m really excited for the courses in &lt;a href="https://www.omscs.gatech.edu/cs-6476-computer-vision" target="_blank">computer vision&lt;/a> and &lt;a href="http://www.omscs.gatech.edu/cs-8803-artificial-intelligence-robotics" target="_blank">AI for robotics&lt;/a>. I&amp;rsquo;ve actually been actively strategizing all the courses for about 18 months (I know, too long). &lt;a href="https://omscentral.com/" target="_blank">OMSCentral&lt;/a> is a great resource.&lt;/p>
&lt;h3 class="relative group">Regression discontinuity okay
&lt;div id="regression-discontinuity-okay" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#regression-discontinuity-okay" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;blockquote class="twitter-tweet" data-lang="en">&lt;p lang="en" dir="ltr">Finally public! Exciting new work w Mandy Pallais &amp;amp; &lt;a href="https://twitter.com/jmelkers?ref_src=twsrc%5Etfw">@jmelkers&lt;/a>: &amp;quot;Does Online Delivery Increase Access to Education?&amp;quot; &lt;a href="https://t.co/OU5bhVnnXv">https://t.co/OU5bhVnnXv&lt;/a> &lt;a href="https://t.co/LwDc59anKd">pic.twitter.com/LwDc59anKd&lt;/a>&lt;/p>&amp;mdash; Joshua Goodman (@JoshuaSGoodman) &lt;a href="https://twitter.com/JoshuaSGoodman/status/780435239252426752?ref_src=twsrc%5Etfw">September 26, 2016&lt;/a>&lt;/blockquote>
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8">&lt;/script>
&lt;p>&lt;a href="https://scholar.harvard.edu/joshuagoodman" target="_blank">Joshua Goodman&lt;/a> is a professor of public policy at HKS, and he&amp;rsquo;s been doing a study on the effects of OMSCS. The tldr is: he, with co-authors Julia Melkers and Amanda Pallais, use a regression discontinuity design to create a &amp;ldquo;treatment&amp;rdquo; of admitted students (woohoo) and a &amp;ldquo;control&amp;rdquo; of those who just missed an (unknown, but it&amp;rsquo;s in the &lt;a href="https://research.hks.harvard.edu/publications/getFile.aspx?Id=1435" target="_blank">paper&lt;/a>) GPA admissions threshold. They then compare outcomes for both. The really interesting stuff is in the descriptive stats: OMSCS applicants and students are older (average age of 33), mid-career-er, male-er, American-er, and from more diverse educational backgrounds than their on-campus counterparts. Many don&amp;rsquo;t apply to other graduate schools. The main finding is:&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;By satisfying large, previously unmet demand for mid-career training, this single program will boost annual production of American computer science master’s degrees by about eight percent.&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>&amp;ndash; &lt;a href="https://research.hks.harvard.edu/publications/workingpapers/citation.aspx?PubId=11348&amp;amp;type=WPN" target="_blank">Goodman, Melkers and Pallais, 2016&lt;/a>&lt;/p>
&lt;p>EIGHT PERCENT, damn. That&amp;rsquo;s a lot. That&amp;rsquo;s insane.&lt;/p>
&lt;p>I wasn&amp;rsquo;t too surprised by the fact that OMSCS applicants are older and more mid-career and non-traditional - that seems to be how the program was pitched. It was certainly how I heard about it: in the Meetup.com circles of ambitious career transitioners in their early 30s. I&amp;rsquo;m &lt;em>very&lt;/em> surprised that the OMSCS has a worse male/female ratio: only 15% of OMSCS applicants are women, compared to 25% of applicants to the on-campus program.&lt;/p>
&lt;p>I&amp;rsquo;m surprised for two reasons: first, the program seems pitched towards career transitioners, and there is a big cultural push right now to get more women into tech. Ergo RailsBridge, Women Who Code, PyLadies, and so on. Maybe it&amp;rsquo;s the circles I travel in, but I feel like there are a &lt;em>lot&lt;/em> of women entering tech right now?&lt;/p>
&lt;p>Second, the OMSCS&amp;rsquo;s flexibility is perfect for, well, working parents in their 30s! In fact, one of the main reasons I was so excited by the program was that it completely fit into my personal life: I wouldn&amp;rsquo;t have to uproot myself and my husband to pursue my AI/robots dream. Uprooting yourself is easier in your 20s, but once you&amp;rsquo;ve got the &lt;a href="https://en.wikipedia.org/wiki/Two-body_problem_%28career%29" target="_blank">two-body problem&lt;/a>, everything gets stickier. The OMSCS is perfect for that.&lt;/p>
&lt;h3 class="relative group">&lt;a href="https://en.wikipedia.org/wiki/In_bocca_al_lupo" target="_blank">In bocca al lupo&lt;/a>
&lt;div id="in-bocca-al-lupohttpsenwikipediaorgwikiin_bocca_al_lupo" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#in-bocca-al-lupohttpsenwikipediaorgwikiin_bocca_al_lupo" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Me, after learning I got in. Champagne!&lt;/p></description></item><item><title>A very Dirichlet journey</title><link>https://www.angelaambroz.com/posts/a_very_dirichlet_journey/</link><pubDate>Thu, 29 Mar 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/a_very_dirichlet_journey/</guid><description>&lt;p>I&amp;rsquo;ve been learning about hierarchical models in Bayesian statistics lately. This has meant digging into some &lt;a href="https://www.youtube.com/watch?v=nNQdvXfW73E&amp;amp;list=PLFHD4aOUZFp3Fx3rfRkBR0XjP1OCcrYXP&amp;amp;index=11" target="_blank">YouTube micro-lectures&lt;/a>, some &lt;a href="http://www.stat.columbia.edu/~gelman/book/" target="_blank">Gelman&lt;/a>, some &lt;a href="http://docs.pymc.io/notebooks/GLM-hierarchical.html" target="_blank">PyMC3 documentation&lt;/a>. And! Revisiting some of my old problem sets from &lt;a href="https://canvas.harvard.edu/courses/20101/assignments/syllabus" target="_blank">CS109B&lt;/a>.&lt;/p>
&lt;h2 class="relative group">Ye olde pset: Text prediction with naive Bayes
&lt;div id="ye-olde-pset-text-prediction-with-naive-bayes" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#ye-olde-pset-text-prediction-with-naive-bayes" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The old problem set had two main problems. The first was a text analysis/prediction problem. Specifically, given 100 articles and two authors, use word frequency and Bayesian methods to predict which author wrote which article. I can see how this could be extended to, for example, automated categorization of articles or maybe even spam filtering. The methods used were, first, a naive Bayes approach - which assumes that word frequencies are independent of each other (probably not true) and just tries to measure the likelihood of observing some words, $w$, conditional on that author (or category, or whatever), $C_{k}$.&lt;/p>
&lt;p>Here it is for multinomial naive Bayes (looking at word count frequency):
$$p(\mathbf{x} | C_{k}) = \frac{(\sum_{i} x_{i})!}{\prod_{i} x_{i}!}\prod_{i} p_{ki}^{x_i} $$&lt;/p>
&lt;p>Which I stole &lt;a href="https://en.wikipedia.org/wiki/Naive_Bayes_classifier#Multinomial_naive_Bayes" target="_blank">from Wikipedia&lt;/a> and is saying:&lt;/p>
&lt;ul>
&lt;li>The likelihood of these words, $\mathbf{x}$, conditional on it being this person, $C_{k}$, (where we have $k$ people/categories/whatever), &lt;em>is&lt;/em>&lt;/li>
&lt;li>The sum of word frequencies, factorial&lt;/li>
&lt;li>Divided by the product of word frequencies, factorial&lt;/li>
&lt;li>Multiplied by the product of probabilities that &lt;em>that&lt;/em> author used &lt;em>that&lt;/em> word ($p_{ki}^{x_i}$).&lt;/li>
&lt;/ul>
&lt;p>Phew! But basically, we&amp;rsquo;re doing our usual Bayesian thing: we observe some data ($x_i$, word frequencies), and multiply that by our prior ($p_{ki}^{x_i}$, the probability that author $k$ uses those words). The assumption is that authors use words at different probabilities. The &lt;em>other&lt;/em> big assumption is that we can just do simple multiplication, since these word likelihoods are independent. That&amp;rsquo;s probably not the case (e.g. words come in phrases, pairs, other stuff).&lt;/p>
&lt;h2 class="relative group">Dirichlet refresh
&lt;div id="dirichlet-refresh" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#dirichlet-refresh" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>But hey! What if we just &lt;em>know&lt;/em> that that assumption of independence can&amp;rsquo;t hold. Language comes in chunks, after all! Not. Independent. Words. In that case, the pset had us work through a Dirichlet model.&lt;/p>
&lt;p>I really like Dirichlet models! They&amp;rsquo;re the n-dimensional extension of my favorite model, the &lt;a href="http://angelaambroz.com/blog/posts/2018/Mar/06/better_bayesian_betabinomial_bits/" target="_blank">beta-binomial model&lt;/a>. They&amp;rsquo;re also (holy music) a model with conjugate priors. That is, something that has an analytical solution. You don&amp;rsquo;t need to do any Monte Carlo Markov Chain sampling (unless you want to, which whatever, you could want to). But the Dirichlet-multinomial, like the beta-binomial, is Dirichlet going in and Dirichlet coming out.&lt;/p>
&lt;p>The Dirichlet is parametrized by an n-dimensional vector of $\alpha$ - this is similar to the beta being parametrized by two parameters ($\alpha, \beta$). Same deal.&lt;/p>
&lt;p>Here&amp;rsquo;s a helpful comparison visualization, courtesy &lt;a href="https://en.wikipedia.org/wiki/Dirichlet_distribution#/media/File:Dirichlet-3d-panel.png" target="_blank">Wikipedia&lt;/a>:&lt;/p>
&lt;p>From a 2-dimensional beta&amp;hellip;
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f3/Beta_distribution_pdf.svg/600px-Beta_distribution_pdf.svg.png" alt="beta" />
&lt;/figure>
&lt;/p>
&lt;p>&amp;hellip;to a 3-dimensional Dirichlet! Ta da!
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://upload.wikimedia.org/wikipedia/commons/2/2b/Dirichlet-3d-panel.png" alt="dirichlet" />
&lt;/figure>
&lt;/p>
&lt;p>So, just like you can set an uninformed prior by using a beta distribution of $Be(1,1)$, you can do the same for the Dirichlet: $B(1,1,1,1,&amp;hellip;)$. It&amp;rsquo;ll be a flat line or plane!&lt;/p>
&lt;p>The benefit, of course, of using the Dirichlet is that you can now model all those words &lt;em>jointly&lt;/em>: you can say, given this big long list of words that author $k$ wrote, what&amp;rsquo;s the joint probability of those words?&lt;/p>
&lt;h2 class="relative group">Porting from R to Python
&lt;div id="porting-from-r-to-python" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#porting-from-r-to-python" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Alright. So, I do think that building stuff from scratch is a valuable way to learn. And translating my old R pset into Python is a valuable way to dig in. But, oooof. This took forever! It forced me to think through each step, and think about stuff like: (a) what libraries are available in Python with which I can give up? And (b) what is happening at stage N of this interminable math journey? Things like that.&lt;/p>
&lt;p>Okay, naive Bayes was easy. Here it is in Python, courtesy &lt;code>sklearn&lt;/code> (thanks, &lt;code>sklearn&lt;/code>):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sklearn.naive_bayes&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">MultinomialNB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sklearn.metrics&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">confusion_matrix&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># A little convenience function to make my&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># confusion matrix labelled and in % terms (rather than absolute)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">confmat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">predictions&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">columns&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">index&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">confusion_matrix&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">actual&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">predictions&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">columns&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">columns&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">index&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">index&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cm&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;sum&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">axis&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">cm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">lambda&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;sum&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">axis&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Fitting the model, predicting, running through the confusion matrix&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">mnb&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">MultinomialNB&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">mnb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">X_train&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y_train&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">y_preds_mnb&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mnb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">predict&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">X_test&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">confmat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y_test&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y_preds_mnb&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y_test&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unique&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">y_test&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unique&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Err, I should have probably mentioned that my &lt;code>X_{train|test}&lt;/code> are &lt;code>pandas&lt;/code> dataframes of word count frequencies for a bunch of words. That is: each row is an article, each column is a word, and each cell is the number of times that word appears in that article. And my &lt;code>y_{train|test}&lt;/code> are &lt;code>pandas&lt;/code> series of the category (in this case, the author&amp;rsquo;s name): each row is the author&amp;rsquo;s name.&lt;/p>
&lt;p>Fine. That&amp;rsquo;s all fine. I recommend you try this out. Maybe using the &lt;a href="https://www.cs.cmu.edu/~enron/" target="_blank">Enron email archive&lt;/a> - see if you can predict email senders! Woohoo. Or &lt;a href="https://www.theatlantic.com/politics/archive/2017/12/forensic-linguists-tackle-trumps-notorious-flynn-tweet/547898/" target="_blank">analyze Trump&amp;rsquo;s tweets and see which are written by him vs. others&lt;/a>. (&lt;em>&amp;ldquo;Forensic linguistics&amp;rdquo;&lt;/em>, ooh la la.)&lt;/p>
&lt;p>Anyway. What became horrible was when I decided to port a mammoth R function (which was given to us in the pset by the TAs - i.e. we weren&amp;rsquo;t meant to code this from scratch) into Python.&lt;/p>
&lt;h2 class="relative group">Oh noez overflow!
&lt;div id="oh-noez-overflow" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#oh-noez-overflow" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The Harvard TAs had written this gargantuan function to manually calculate the Dirichlet-multinomial posterior for each article. That is, the function would return a floating point likelihood of whether that article was author $A$ or author $B$. I ported it into Python, but won&amp;rsquo;t copy it here (probably violates Harvard copyright?).&lt;/p>
&lt;p>But I did learn some stuff, which relates back to my &lt;a href="https://www.angelaambroz.com/blog/posts/2018/Mar/20/cs50__data_structures_achievement_unlocked/" target="_blank">CS50 learnings&lt;/a>: MEMORY ALLOCATION.&lt;/p>
&lt;p>So Python is dynamically typed, i.e. duck typed, i.e. if it looks and quacks like an &lt;code>int&lt;/code>, it&amp;rsquo;s an &lt;code>int&lt;/code>! Which is fine and well for 90% of what you do. But sometimes &lt;a href="https://www.angelaambroz.com/blog/posts/2018/Mar/13/writing_better_python/" target="_blank">you want to be explicit&lt;/a>. Sometimes you also just plain overflow.&lt;/p>
&lt;p>Overflow is when you run out of memory. Say you want to hold a really big number in memory. Like, $e^{710}$. Well, you can&amp;rsquo;t. There aren&amp;rsquo;t enough bits in your memory for that to happen. Sort of. Python actually, for integers, will just take up ALL the memory available and, dammit, give you your number. But this breaks down for floating points. Because, then you need all the numbers to the right and the left of the decimal point - and that&amp;rsquo;s a tradeoff! You tradeoff size and precision. This is also why some floating points get &amp;ldquo;rounded&amp;rdquo; by Python under the hood - for example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Ten decimal places: all looks well&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.10f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 0.3333333333&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Twenty, and we see the lies we&amp;#39;ve been told&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.20f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 0.33333333333333331483&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ANYWAY. All this to say, I was trying to make my Dirichlet posterior function, and it kept crapping out at, yep, $e^{710}$. And the way it crapped out varied by basic Python vs. &lt;code>numpy&lt;/code> vs. my eventual savior, the &lt;code>decimal&lt;/code> module (&lt;a href="https://docs.python.org/2/library/decimal.html" target="_blank">docs&lt;/a>).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">decimal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">709&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 8.218407461554972e+307&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">710&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ---------------------------------------------------------------------------&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># OverflowError Traceback (most recent call last)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># &amp;lt;ipython-input-11-0ad1e5224725&amp;gt; in &amp;lt;module&amp;gt;()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ----&amp;gt; 1 math.exp(710)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># OverflowError: math range error&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">709&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 8.2184074615549724e+307&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">710&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># RuntimeWarning: overflow encountered in exp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># inf&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">decimal&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">709&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Decimal(&amp;#39;8.218407461554972189241372387E+307&amp;#39;)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">decimal&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">710&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Decimal(&amp;#39;2.233994766161711031253644458E+308&amp;#39;)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ah ha! Bottom line, use &lt;code>decimal&lt;/code> and you may math with ease. Or use &lt;code>numpy&lt;/code> for their amusing &amp;ldquo;so big, basically infinite!&amp;rdquo;&lt;/p></description></item><item><title>Progress pics- Portraits</title><link>https://www.angelaambroz.com/posts/progress_pics_portraits/</link><pubDate>Sat, 24 Mar 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/progress_pics_portraits/</guid><description>&lt;p>I really adore progress pics, which is a thing I discovered when I discovered (or, rather, figured out how to use) Reddit. I know, I know. Don&amp;rsquo;t shame me, I love &lt;a href="https://www.reddit.com/r/ImaginaryLandscapes/" target="_blank">r/ImaginaryLandscapes&lt;/a> and &lt;a href="https://www.reddit.com/r/ColorizedHistory/" target="_blank">r/colorizedhistory&lt;/a> and there are lots of good, sane subreddits.&lt;/p>
&lt;p>Anyway. Progress pics are great - super inspiring and motivating. So I wanted to include a few &amp;ldquo;progress pics&amp;rdquo; from my drawing earlier this year. I&amp;rsquo;m trying to improve my general craftsmanship on a bunch of stuff: proportion, perspective, shading, color. I&amp;rsquo;m also trying to branch &lt;em>away&lt;/em> from portraits, which I do too much of. &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/22/gamifying_art/" target="_blank">Here&amp;rsquo;s some more thoughts on my Art Journey, including the tools I&amp;rsquo;m using&lt;/a>.&lt;/p>
&lt;p>Despite trying to move away from portraits, here are three portraits - made one after the other - of the wonderful Star Trek: Discovery characters.&lt;/p>
&lt;p>First, Michael Burnham (played by Sonequa Martin-Green). &lt;a href="https://www.spotern.com/en/spot/tv/star-trek-discovery/90560/starfleet-magne-tic-insi-gnia-badge-worn-by-first-officer-michael-burnham-sonequa-martin-green-as-seen-in-star-trek-discovery-s01e02" target="_blank">Reference pic here.&lt;/a>&lt;/p>
&lt;p>Next, tentatively trying my new colored pencils on Gabriel Lorca (played by Jason Isaacs). &lt;a href="https://i2.wp.com/tgnreview.com/wp-content/uploads/2018/02/Mirror-lorca.jpg?ssl=1" target="_blank">Reference pic.&lt;/a>&lt;/p>
&lt;p>And finally, getting bolder at colors, Philippa Georgiou (played by Michelle Yeoh). &lt;a href="http://www.fanpop.com/clubs/philippa-and-michael/images/40742545/title/captain-philippa-georgiou-fanart" target="_blank">Reference pic.&lt;/a>&lt;/p>
&lt;p>I see a bunch of flaws with the above - but I&amp;rsquo;m happy with how much each is an improvement on the last. I&amp;rsquo;m also happy that, &lt;em>in general&lt;/em>, they resemble their reference pics (and the actors), even if it&amp;rsquo;s still not perfect. I really loved doing the colors on the Georgiou portrait, especially around the eyes. It blows the Lorca portrait colors out of the water! So that&amp;rsquo;s nice.&lt;/p></description></item><item><title>PyLadies DC - Intro to data science workflow</title><link>https://www.angelaambroz.com/posts/pyladies_dc__intro_to_data_science_workflow/</link><pubDate>Fri, 23 Mar 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/pyladies_dc__intro_to_data_science_workflow/</guid><description>&lt;p>I led a tutorial for the &lt;a href="https://www.meetup.com/dc-pyladies/" target="_blank">DC PyLadies&lt;/a> group titled, &lt;em>An introduction to the data science workflow in Python&lt;/em>. Here are the &lt;a href="https://github.com/angelaambroz/2018_03_pyladies" target="_blank">materials&lt;/a>, which I hope will live on in usefulness.&lt;/p>
&lt;p>The workshop covered: (1) getting data (with examples of CSV loading, SQL querying, and API calling), (2) cleaning data (with some visualizations in &lt;code>matplotlib&lt;/code>), and (3) modeling data (fitting a linear regression using three libraries - &lt;code>statsmodels&lt;/code>, &lt;code>scikit-learn&lt;/code> and plain ol&amp;rsquo; &lt;code>numpy&lt;/code> - and confirming the coefficients are the same).&lt;/p>
&lt;h2 class="relative group">Prep
&lt;div id="prep" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#prep" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>My goal for the workshop was to give a &amp;ldquo;tour&amp;rdquo; of the common Python packages used in data science. This was aimed towards women who might have some experience doing data analysis in R, Stata, or something else, and thus needed to get a handle on &lt;em>where&lt;/em> to find their favorite stats/machine learning methods in the world of Python (rather than &lt;em>how&lt;/em> those methods worked - i.e. I didn&amp;rsquo;t want this to be a stats class).&lt;/p>
&lt;p>I ran a survey beforehand to also get a sense of how new to Python attendees were (by asking a couple &amp;ldquo;beginner&amp;rdquo; questions, like, &lt;em>What does &lt;code>import some_library&lt;/code> do?&lt;/em>), what other programming languages they knew, and what they were most excited about learning. This helped &lt;em>a lot&lt;/em>, since I knew what I wanted to present (supply!) but I also knew I wanted to meet folks where they were at (demand!).&lt;/p>
&lt;h2 class="relative group">Logistics
&lt;div id="logistics" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#logistics" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I used &lt;a href="https://nedbatchelder.com/blog/201210/pizzapy.html" target="_blank">Ned Batchelder&amp;rsquo;s &lt;code>pizza.py&lt;/code> script to calculate how many pizzas to order&lt;/a>. Ned organizes the extremely popular (and very great) &lt;a href="https://www.meetup.com/bostonpython/" target="_blank">Boston Python User Group&lt;/a>, and he is wise in the ways of Meetup. Specifically, notorious Meetup attrition (only about 50% of RSVPs usually show up). Anyway, would you believe it - we had &amp;lt;1 pizza left over - &lt;code>pizza.py&lt;/code> really came through!&lt;/p>
&lt;p>To bypass Installation Hell - wherein 33% of a workshop is spent trying to get some version of Python installed on some attendee&amp;rsquo;s machine - I used &lt;a href="https://mybinder.org/" target="_blank">Binder&lt;/a>, which I found via &lt;a href="https://jvns.ca/blog/2017/11/12/binder--an-awesome-tool-for-hosting-jupyter-notebooks/" target="_blank">Julia Evans&amp;rsquo;s blog&lt;/a>. Binder is SUPER convenient: you make your repo with your Jupyter notebooks (and a &lt;code>requirements.txt&lt;/code>), point Binder to it, and it&amp;rsquo;ll launch that repo as a Docker container that people can access and interact with. This was really great, since we could skip the installation pain and get straight to it.&lt;/p>
&lt;h2 class="relative group">The challenges of pedagogy
&lt;div id="the-challenges-of-pedagogy" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-challenges-of-pedagogy" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I love teaching, and I love learning. I also love thinking about learning - that mystical moment when you &lt;em>get&lt;/em> something - and reflecting on how and why Things Are Learned. Teaching is a special challenge because you want to be engaging (fun!) and clear. (David Malan, who teaches &lt;a href="http://angelaambroz.com/blog/posts/2018/Mar/20/cs50__data_structures_achievement_unlocked/" target="_blank">CS50&lt;/a>, is a master at this.) Being &lt;em>clear&lt;/em>, especially about stuff that either is complex or is commonly perceived to be complex, is hard. I think it&amp;rsquo;s very important to be clear - most big human ideas can be boiled down to something quite simple. I strongly believe in &lt;a href="https://www.youtube.com/watch?v=JC82Il2cjqA" target="_blank">this ad by Khan Academy&lt;/a> - human knowledge is a set of simple building blocks. Also, to paraphrase Richard Feynman, if you can&amp;rsquo;t explain it in simple terms, you don&amp;rsquo;t understand it.&lt;/p>
&lt;p>So, anyway, I tried to do that - but it was pretty exhausting. I was definitely pooped by the end - and dehydrated! I did appreciate the opportunity, though, and hope to get better at it. Bottom line is I find a lot of inspiration in teaching/learning, and have become super &lt;a href="https://www.goodreads.com/book/show/40745.Mindset" target="_blank">growth mindset&lt;/a> lately.&lt;/p></description></item><item><title>CS50 - Data structures achievement unlocked</title><link>https://www.angelaambroz.com/posts/cs50__data_structures_achievement_unlocked/</link><pubDate>Tue, 20 Mar 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/cs50__data_structures_achievement_unlocked/</guid><description>
&lt;h2 class="relative group">Well, Prof. David Malan liked my tweet so&amp;hellip;
&lt;div id="well-prof-david-malan-liked-my-tweet-so" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#well-prof-david-malan-liked-my-tweet-so" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;blockquote class="twitter-tweet" data-lang="en">&lt;p lang="en" dir="ltr">A volcano. A plume of smoke roars up into the steel grey sky. Angela walks towards you, framed in red fiery light, carrying - on her shoulders - the dead carcass of a hash table of linked lists. This is &lt;a href="https://twitter.com/cs50?ref_src=twsrc%5Etfw">@cs50&lt;/a> pset5! She raises her C sword and frees some more memory. &amp;quot;Raaaah!&amp;quot;&lt;/p>&amp;mdash; Angela Ambroz (@angelaambroz) &lt;a href="https://twitter.com/angelaambroz/status/976068550438871041?ref_src=twsrc%5Etfw">March 20, 2018&lt;/a>&lt;/blockquote>
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8">&lt;/script>
&lt;p>I&amp;rsquo;m so pleased.&lt;/p>
&lt;h2 class="relative group">Data structures are complicated
&lt;div id="data-structures-are-complicated" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#data-structures-are-complicated" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;m also pleased because I feel like I reached peak CS50 this past week. Where by &amp;ldquo;week&amp;rdquo;, I mean &amp;ldquo;month&amp;rdquo;. Life happened, but this was also the densest part of the course and I wanted to take my time. It was hard, brain-sweaty work and it was &lt;em>awesome&lt;/em>. And it was over far too soon. I want to take a full course on data structures and algorithms, because the ~6 hours of struggle on problem set 6 were definitely not enough. Definitely need more hours on this. MORE HOURS.&lt;/p>
&lt;p>For my problem set, I implemented a hash table with linked lists, and fumbled through &lt;code>malloc()&lt;/code> (&lt;a href="http://www.angelaambroz.com/blog/posts/2018/Feb/12/cs50__algorithms/" target="_blank">nightmare of &lt;code>malloc()&lt;/code>!&lt;/a>) and freeing memory. Apparently, I free up too much memory every time. &lt;code>valgrind&lt;/code> (a command-line utility which checks your C program for any memory leaks) usually complained that I had allocated space for 3 things and freed 5. Woops. I JUST WANT TO BE SURE.&lt;/p>
&lt;h2 class="relative group">Pedagogical meta-ness
&lt;div id="pedagogical-meta-ness" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#pedagogical-meta-ness" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>These &amp;ldquo;Dense Materials, Ahoy!&amp;rdquo; lectures are longer (1hr 45min) than the earlier weeks. The &amp;ldquo;shorts&amp;rdquo; - additional videos where a CS50 staff member goes in more detail - are, cumulatively, another ~2 hours or so. This is a lot of content! It takes forever, but - again - I loved it and feel hashtag-blessed that we have this resource available, for free, on the intertoobs. I really agree with &lt;a href="https://www.reddit.com/r/cs50/comments/84ah7y/4_years_after_cs50/dvoyiw5/" target="_blank">this gushing Reddit post, too&lt;/a> - the problem sets are challenging grinds, but they&amp;rsquo;re not impossible, and I feel like I learn a lot from them.&lt;/p>
&lt;h2 class="relative group">Main takeaways
&lt;div id="main-takeaways" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#main-takeaways" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Welp, now I know how to define my own data types in C with &lt;code>typedef struct&lt;/code>. Wooo hooooo.&lt;/li>
&lt;li>Learned about a bunch of data structures: linked lists, hash tables, tries, stacks, queues. Only implemented a hash table with linked lists, and still feel shaky on pointing my pointers to the right places. I &lt;em>wanted&lt;/em> to try a trie, but - at 6-hour pset mark - I was pretty pooped.&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Looking ahead: Lectures &amp;amp; psets
&lt;div id="looking-ahead-lectures--psets" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#looking-ahead-lectures--psets" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I feel like I just climbed a hill in my bike, and my thighs and lungs are burning, and I&amp;rsquo;m pretty sure I&amp;rsquo;m gonna die - but now it&amp;rsquo;s the speedy, easy, thrilling descent. The next problem sets are all Python, JavaScript and SQL. i.e. My old friends. The next three (!) lectures don&amp;rsquo;t even have a pset. So the course&amp;rsquo;s marginal added value to me will be lower in this second half.&lt;/p>
&lt;h2 class="relative group">Looking ahead: Final project thoughts
&lt;div id="looking-ahead-final-project-thoughts" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#looking-ahead-final-project-thoughts" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>After the lectures and psets, there is the final project. I found this book the other day - &lt;a href="http://www.buildyourownlisp.com/contents" target="_blank">&lt;em>Build Your Own Lisp&lt;/em>&lt;/a> - and am thinking of using it in my final project, since I&amp;rsquo;ve always wanted to know how &amp;ldquo;higher-level&amp;rdquo; programming languages work. e.g. The most widely-used implementation of Python is &lt;a href="https://stackoverflow.com/a/9452140/" target="_blank">written in C&lt;/a>, and I was always like, &amp;ldquo;But what does that &lt;em>mean?&lt;/em>&amp;rdquo;&lt;/p>
&lt;p>I&amp;rsquo;m also interested in investigating the intersection between natural and programming languages: specifically, every programming language I&amp;rsquo;ve seen is written in English. I wonder if there&amp;rsquo;s any effect, then, of how all our technology is written in English - e.g. is there a &lt;a href="https://en.wikipedia.org/wiki/Linguistic_relativity" target="_blank">Sapir-Whorf effect&lt;/a> where even fundamental computer science paradigms would be re-envisioned if the higher-level languages had been written in, say, हिंदी ?&lt;/p>
&lt;p>(My prior is actually, no, the effect is probably limited, since low-level programming languages are just math and logic, which are a universal language. It&amp;rsquo;s all binary underneath, after all. &lt;em>Maybe&lt;/em> there&amp;rsquo;d be some effect as you go further up the levels of abstraction, e.g. Python, Ruby, etc.)&lt;/p>
&lt;p>Anyway, I&amp;rsquo;m really looking forward to more CS50!&lt;/p></description></item><item><title>Writing better Python</title><link>https://www.angelaambroz.com/posts/writing_better_python/</link><pubDate>Tue, 13 Mar 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/writing_better_python/</guid><description>&lt;p>I started incorporating a few new tools into my programming lately, and it&amp;rsquo;s been rad. I wanted to share how and why I think these tools are helpful. They may be standard to software engineers, but - as a data scientist, and someone without a formal CS background (ahem, &lt;em>for now!&lt;/em>) - these sorts of programming paradigms aren&amp;rsquo;t always as prioritized. But it&amp;rsquo;s good to change that!&lt;/p>
&lt;p>I&amp;rsquo;ve been filling in my CS foundations with &lt;a href="http://angelaambroz.com/blog/posts/2018/Feb/12/cs50__algorithms/" target="_blank">CS50&lt;/a> lately, and - beyond the big stuff like data structures and algorithms - I feel like C is giving me good &amp;ldquo;everyday&amp;rdquo; habits of being explicit about my data types and more serious about adhering to programming styles. Remember: code is read X times more than it&amp;rsquo;s written, so standardizing your style improves readability/makes you better!&lt;/p>
&lt;p>I&amp;rsquo;ve started incorporating some better programming practices into my day-to-day, and I really like the results. Namely:&lt;/p>
&lt;h2 class="relative group">Logging
&lt;div id="logging" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#logging" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>My style of coding - which I assume is pretty common - is something like:&lt;/p>
&lt;ol>
&lt;li>(Semi-optional) Pseudo code/sketch something out, if it&amp;rsquo;s complicated-seeming&lt;/li>
&lt;li>Bash something out in Python/Clojure/JavaScript/C&lt;/li>
&lt;li>Run it and see what happens&lt;/li>
&lt;li>Try to understand inevitable error message&lt;/li>
&lt;/ol>
&lt;p>In the beginning, step (4) was mostly impossible, and so I sprinkled &lt;code>print()&lt;/code> statements liberally throughout my code. Then I&amp;rsquo;d sort of anxiously watch the terminal to see what &lt;code>stdout&lt;/code> would say as my program ran.&lt;/p>
&lt;p>As I got better at reading error messages and generally more confident, I used &lt;code>print()&lt;/code> less. But it&amp;rsquo;s still something that I&amp;rsquo;ll use when something breaks in a way I&amp;rsquo;m not expecting.&lt;/p>
&lt;p>And that&amp;rsquo;s fine. But, at the same time, I saw how some of my senior colleagues used &lt;code>logging&lt;/code> - and, generally, talked a lot about logs. Searching logs. Logs getting big. Finding something in the logs. Like&amp;hellip; what are these logs you people keep talking about? Time to learn!&lt;/p>
&lt;p>Python&amp;rsquo;s standard library includes the &lt;a href="https://docs.python.org/2/library/logging.html" target="_blank">&lt;code>logging&lt;/code>&lt;/a> module. The general idea is that, instead of using &lt;code>print()&lt;/code> statements - which write to &lt;code>stdout&lt;/code> (i.e. your shell&amp;rsquo;s output) - and then disappear into the mists of time, logs are saved to a &lt;code>.log&lt;/code> file for as long as you like, so you can peruse as much as you like. (Or, better yet, do cool data analysis on them.)&lt;/p>
&lt;p>Logging in Python is really straightforward. The basic steps are:&lt;/p>
&lt;ol>
&lt;li>Configure a log file: its name and file path, its formatting, and what it&amp;rsquo;ll pick up (there are &lt;a href="https://docs.python.org/2/library/logging.html#logging-levels" target="_blank">six levels&lt;/a> of logging in Python).&lt;/li>
&lt;li>Sprinkle log messages throughout!&lt;/li>
&lt;li>Profit!&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">logging&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">basicConfig&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">static&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="vm">__name__&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">.log&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">level&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DEBUG&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">format&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">%(name)s&lt;/span>&lt;span class="s2"> - &lt;/span>&lt;span class="si">%(asctime)s&lt;/span>&lt;span class="s2"> - &lt;/span>&lt;span class="si">%(levelname)s&lt;/span>&lt;span class="s2"> - &lt;/span>&lt;span class="si">%(message)s&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">filemode&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;w&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That is, configure a &lt;code>.log&lt;/code> file named (dynamically) after the &lt;code>__name__&lt;/code> (i.e. &lt;a href="https://stackoverflow.com/questions/419163/what-does-if-name-main-do/419185#419185" target="_blank">the name of the Python module currently being executed&lt;/a>), catch all priority levels (from &lt;code>DEBUG&lt;/code> and up), format the output with the &lt;code>name&lt;/code> of the logger, the local time when that log statement was written (&lt;code>asctime&lt;/code>), the level of priority (&lt;code>DEBUG&lt;/code>, &lt;code>CRITICAL&lt;/code>, etc.), and the &lt;code>message&lt;/code> (which you&amp;rsquo;ll define later). Do all this and write (&lt;code>w&lt;/code>) to the file, rewriting if it already exists (you can change this to append, &lt;code>a&lt;/code>, if you prefer).&lt;/p>
&lt;p>Later in the code, I initiated my &lt;code>logger&lt;/code> object and wrote my first message (an &lt;code>INFO&lt;/code> message):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getLogger&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Starting log...&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>A &lt;code>.log&lt;/code> file is born!&lt;/p>
&lt;p>Yet later, while I was running a gnarly loop that tried to do some stats on a bunch of things, I logged every model like so:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">thing_id&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;ID &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">thing_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">b0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">some_fitting_function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">thing_id&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s1">&amp;#39;Parameters: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">b0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b1&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">warning&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Failed to fit&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That way, I kept track of everything I was able to fit a model to, and everything that failed. By using a &lt;code>try&lt;/code>/&lt;code>except&lt;/code> block, my loop kept running. It was super handy, since I needed this to run for a while, for thousands of things, and I was actually trying to get a sense of how often it would fail to fit (and why).&lt;/p>
&lt;h2 class="relative group">Type hints
&lt;div id="type-hints" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#type-hints" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Python is dynamically typed - meaning you don&amp;rsquo;t have to specify your data types (string, integer, float), and they&amp;rsquo;re inferred when compiling. C, on the other hand, is much more explicit. Consider the same code in Python vs. C:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;hello&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">z&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.14&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">char&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">[]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;hello&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="n">y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">float&lt;/span> &lt;span class="n">z&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.14&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Like, C doesn&amp;rsquo;t even have a &lt;code>string&lt;/code> datatype! It only has an array of characters! So you have to literally tell it, hey, I&amp;rsquo;m going to make an array, &lt;code>x[]&lt;/code>, of characters, &lt;code>char&lt;/code>, and those characters are &lt;code>h&lt;/code>, &lt;code>e&lt;/code>, &lt;code>l&lt;/code>, &lt;code>l&lt;/code>, &lt;code>o&lt;/code>. Mamma mia.&lt;/p>
&lt;p>Actually, I kid. I love that C does this. I love that an &lt;a href="https://stackoverflow.com/a/1641963" target="_blank">array name is the pointer to the 0th element&lt;/a>. And I actually also love the types! It makes the code more readable.&lt;/p>
&lt;p>So now I discovered the best of both worlds with gradual typing.&lt;/p>
&lt;p>&lt;span class="caption">Google auto-complete drama&lt;/span>&lt;/p>
&lt;p>When I was recently trying to &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/10/understanding_a_big_wide_codebase/" target="_blank">understand a big, wide codebase&lt;/a>, I was starting to get annoyed that I&amp;rsquo;d have to constantly go up and down the function stack to try to understand what the hell that one argument was. It&amp;rsquo;s hard to tell what function &lt;code>foo(arg)&lt;/code> is expecting for &lt;code>arg&lt;/code> if it&amp;rsquo;s something like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># do some stuff&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">deep_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">deep_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># do different stuff&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">deeper_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">deeper_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># for the love of god&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># what is going on here&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">deepest_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">deepest_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># arg is an int!! AN INT!!!!&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I&amp;rsquo;d be spelunking up and down the function stack, trying to write down what &lt;code>arg&lt;/code> was and keep it in mind. But for a &lt;em>lot&lt;/em> of parameters and a &lt;em>lot&lt;/em> of functions, spread across multiple modules.&lt;/p>
&lt;p>This was when I decided that I would spelunk ONCE AND FOR ALL and just type hint everything up and down. Type hinting is great. You basically state, in your &lt;code>foo()&lt;/code>, what type &lt;code>arg&lt;/code> is, what type &lt;code>foo()&lt;/code> returns. It works for keyword arguments too. It&amp;rsquo;s very flexible. You can type hint a couple parameters, skip others, and so on. You can use the usual data types (&lt;code>str&lt;/code>, &lt;code>int&lt;/code>, &lt;code>float&lt;/code>, &lt;code>bool&lt;/code>), but you can also type hint user-created types and classes.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># do some stuff&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">deep_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">deep_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># do different stuff&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">deeper_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">deeper_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># for the love of god&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># what is going on here&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">deepest_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">deepest_foo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">arg&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># arg is an int!! AN INT!!!!&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You can also put your type hints in a &lt;a href="https://www.python.org/dev/peps/pep-0484/#stub-files" target="_blank">stub file&lt;/a>. The benefits of using type hints, as I see them, are:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Readability&lt;/strong>. No more spelunking. Better understanding of what each function is doing.&lt;/li>
&lt;li>&lt;strong>IDEs&lt;/strong>. I learned a lot about type hints by watching &lt;a href="https://www.youtube.com/watch?v=o64FV-ez6Gw" target="_blank">Joel Grus live-code a neural net in 1 hr&lt;/a>. His IDE (Visual Studio Code) and many others are smart about type hints and will raise a flag if you&amp;rsquo;re not being internally consistent.&lt;/li>
&lt;li>&lt;strong>Linting&lt;/strong>. Linters also do logic checks on internal consistency with types.&lt;/li>
&lt;/ul>
&lt;p>Which brings me to&amp;hellip;&lt;/p>
&lt;h2 class="relative group">Linting
&lt;div id="linting" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#linting" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Did you know &lt;code>pylint&lt;/code> gives your code a SCORE? YES. A SCORE. No longer will you kind of vaguely feel like your code is fine, but could be improved. NO. Now you know whether your code is a 4.32/10 or 6.16/10 or 8.23/10!&lt;/p>
&lt;p>So &lt;code>pylint&lt;/code> was another thing I long glossed over, but - when I discovered that it QUANTIFIES YOUR CODE QUALITY - well, you can bet I&amp;rsquo;m on that train. So now I &lt;code>pylint&lt;/code> everything I can. My emails, my blog posts. All PEP8 everything, dammit!&lt;/p>
&lt;p>What &lt;code>pylint&lt;/code> does is automatically check your &lt;code>.py&lt;/code> files for adhering to style standards (&lt;a href="https://www.python.org/dev/peps/pep-0008/" target="_blank">PEP8 style guide&lt;/a>), but also handy stuff like software design rules of thumb. For example, it&amp;rsquo;ll encourage you to refactor a function into more functions (or a class!) if that function has more than five arguments. I guess this is what I hear people at work call a &amp;ldquo;code smell&amp;rdquo;. When I googled some of &lt;code>pylint&lt;/code>&amp;rsquo;s output messages, I found this wonderful resource: &lt;a href="http://pylint-messages.wikidot.com/" target="_blank">PyLint Messages - and what they&amp;rsquo;re trying to tell you&lt;/a>.&lt;/p>
&lt;p>Again, you can configure your IDE to adhere to PEP8 guidelines too - making it even easier.&lt;/p>
&lt;h2 class="relative group">Resources
&lt;div id="resources" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#resources" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h3 class="relative group">Logging
&lt;div id="logging-1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#logging-1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=g8nQ90Hk328" target="_blank">Socratica: Logging in Python || Learn Python Programming (Computer Science)&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.patricksoftwareblog.com/python-logging-tutorial/" target="_blank">Patrick&amp;rsquo;s Software Blog: Python Logging Tutorial&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 class="relative group">Type hints
&lt;div id="type-hints-1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#type-hints-1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=2wDvzy6Hgxg" target="_blank">Type Hints - Guido van Rossum - PyCon 2015&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 class="relative group">Linting
&lt;div id="linting-1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#linting-1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://pylint-messages.wikidot.com/" target="_blank">PyLint Messages&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Better Bayesian beta-binomial bits</title><link>https://www.angelaambroz.com/posts/better_bayesian_betabinomial_bits/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/better_bayesian_betabinomial_bits/</guid><description>&lt;p>Yesterday at work, I gave an internal talk on the &lt;a href="https://en.wikipedia.org/wiki/Beta-binomial_distribution" target="_blank">beta-binomial model&lt;/a>, AKA my beloved Bayesian conjugate prior model. I&amp;rsquo;ve been using it a lot recently for A/B testing analysis, usually as a complement (not replacement!) to the usual frequentist methods (e.g. running a t-test between the cohorts, checking cohort balance before and after the experiment, running regressions to control for stuff that may be imbalanced). I&amp;rsquo;ve been reading a lot of &lt;a href="http://www.andrewgelman.com" target="_blank">Gelman&lt;/a> lately, and just getting more and more enamored with the Bayesian view, and the failings (ahem) of the frequentists.&lt;/p>
&lt;p>Specifically, what I like is:&lt;/p>
&lt;ul>
&lt;li>Rather than worrying about &lt;em>sampling distributions&lt;/em> (which is core to frequentist stats), you can speak more intuitively about &lt;em>beliefs&lt;/em>.&lt;/li>
&lt;li>You have to be &lt;em>explicit&lt;/em>. That is, instead of a bunch of hidden assumptions about how your parameters or your data are distributed, you make those choices yourself - they&amp;rsquo;re knobs to turn.&lt;/li>
&lt;li>In the case of conjugate priors, the math is super &lt;em>easy&lt;/em>. Updating a conjugate prior - such as updating a beta distribution with binomial data - is just so damn simple. And it&amp;rsquo;s lovely!&lt;/li>
&lt;/ul>
&lt;p>I also just really love how the beta can be generalized into n-dimensional space into the &lt;a href="https://en.wikipedia.org/wiki/Dirichlet_distribution" target="_blank">Dirichlet&lt;/a>. Back in &lt;a href="https://canvas.harvard.edu/courses/20101/assignments/syllabus" target="_blank">CS109B&lt;/a>, we did a cool homework where we Bayesian-updated the Dirichlet distribution of two texts to see if we could determine the author. Hollaaaa, NLP!&lt;/p>
&lt;p>One good question that came up during my talk yesterday was: &lt;em>When is this useful? When is it more useful than the usual (frequentist) methods?&lt;/em>&lt;/p>
&lt;p>My sense is that it&amp;rsquo;s most useful when you &lt;strong>don&amp;rsquo;t have much data&lt;/strong> (or don&amp;rsquo;t expect to have much data). As $n \rightarrow \infty$, Bayesian and frequentist methods should agree. But there&amp;rsquo;s a big wide world out there of sparse data and low sample sizes!&lt;/p>
&lt;p>For example, in the case of views on a single YouTube video - the distribution of views across videos on YouTube has a &lt;em>very&lt;/em> long tail: most videos get little to no views, and a minority get a whole lot. But what if you want to predict stuff on that long tail? A low-data area where you don&amp;rsquo;t expect much data to (ever) come? That&amp;rsquo;s where Bayes can really shine.&lt;/p>
&lt;p>Or, heh, SHINE WITH THE FIRE OF BAD ASSUMPTIONS! But at least they&amp;rsquo;re explicit. Not-much-data means your prior grows in importance.&lt;/p>
&lt;p>As I type, the &lt;a href="http://wimlds.org/" target="_blank">Women in Machine Learning and Data Science&lt;/a> conference is happening/has happened. One of the talks was from the very cool &lt;a href="https://twitter.com/stitchfix_algo" target="_blank">StitchFix Algorithms&lt;/a> team, on - gasp! - using the beta-binomial for predicting sales of slow-moving items! Very cool.&lt;/p></description></item><item><title>Build Your Own Lisp- Learn C and Build Your Own Programming Language (2014) - ⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/build_your_own_lisp_learn_c_and_build_your_own_programming_language/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/build_your_own_lisp_learn_c_and_build_your_own_programming_language/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/build_your_own_lisp_learn_c_and_build_your_own_programming_language/book_jacket_hu52d6bd3282bef3202b60891387280648_41860_330x0_resize_q75_box.jpg 330w,
/posts/build_your_own_lisp_learn_c_and_build_your_own_programming_language/book_jacket_hu52d6bd3282bef3202b60891387280648_41860_660x0_resize_q75_box.jpg 660w,
/posts/build_your_own_lisp_learn_c_and_build_your_own_programming_language/book_jacket_hu52d6bd3282bef3202b60891387280648_41860_1024x0_resize_q75_box.jpg 1024w,
/posts/build_your_own_lisp_learn_c_and_build_your_own_programming_language/book_jacket_hu52d6bd3282bef3202b60891387280648_41860_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/build_your_own_lisp_learn_c_and_build_your_own_programming_language/book_jacket_hu52d6bd3282bef3202b60891387280648_41860_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Daniel Holden&lt;/li>
&lt;li>Number of pages: 212&lt;/li>
&lt;li>Year published: 2014&lt;/li>
&lt;li>Year read: 2018&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Aghh. This is hovering between a did-not-finish (at 69%) and a &amp;ldquo;want to read&amp;rdquo; for me. I might pick it up again.&lt;br/>&lt;br/>Basically: I picked this up because I had two goals - (1) I wanted to write a toy programming language for my &lt;a href="https://cs50.harvard.edu/">CS50&lt;/a> final project, and (2) I wanted to do more C. &lt;br/>&lt;br/>Unfortunately, this book started strong but then lost a lot of steam for me. Plus, I found Destroy All Software&amp;rsquo;s &lt;a href="https://www.destroyallsoftware.com/screencasts/catalog/a-compiler-from-scratch">A compiler from scratch&lt;/a> video, which was basically the final nail in the coffin.&lt;br/>&lt;br/>This book has two goals, and they&amp;rsquo;re admirable: first, introduces people to the basic theory behind how programming languages are interpreted/compiled, and, second, it teaches them C. The process is very similar to Destroy All Software&amp;rsquo;s video: you read in some input string, you tokenize those strings according to your language, you parse them into an appropriate tree structure, and then you pipe that tree into the compilation language. In the case of this book, you do all of that process: input, tokenize, parse, and compile in C. In Destroy All Software, he does the inputting, tokenizing and parsing in Ruby and then - mysteriously/wackily - compiles to JAVASCRIPT (what in the world). I&amp;rsquo;m planning to parse/tokenize/etc in Python and compile to C.&lt;br/>&lt;br/>I made serious headway with the book, but eventually found myself just pecking out 100s of lines of C without understanding what the eff was going on. And the reason is that I think this book&amp;rsquo;s second goal - to assume it&amp;rsquo;s understandable to C beginners - isn&amp;rsquo;t really realistic. I have about ~20 hours of C under my belt (i.e. 5 problem sets in CS50), and I have a shaky grasp of pointers and memory allocation, and this book quickly got away from me. I ended up just blindly trying stuff, but then I was - well - struggling with C concepts, rather than compiler concepts. With the DAS video, instead, I&amp;rsquo;ve switched to Python and am finding it &lt;em>much&lt;/em> easier to follow - now, instead of getting lost in the syntax of my parsing language, I can just focus on building a compiler.&lt;br/>&lt;br/>Oh yeah, and another point: the author abstracts some of the tokenizing away from you with a custom-built C library he wrote called &lt;code>mpc&lt;/code>. I&amp;rsquo;m not sure about the pedagogy, but - in general - I don&amp;rsquo;t like it when books provide custom-built libraries that you need to do to work, e.g. Allen Downey (who I generally admire very much!) did this with &lt;a href="https://www.goodreads.com/review/show/1629140056?book_show_action=false&amp;from_review_page=1">Think Stats&lt;/a> and it kinda killed the book for me - let the reader build from the smallest building blocks! Don&amp;rsquo;t give us a half-built contraption upon which we&amp;rsquo;re meant to build more - that just means we spend more time trying to figure out the contraption!&lt;br/>&lt;br/>Anyway, I feel bad saying all this. I think the book would be GREAT for people that are already up to speed with C. Also, it&amp;rsquo;s free and the author offers a lot of humor and encouragement. Bah!&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/24666409" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>CS50 - Algorithms, pointers and malloc, oh my</title><link>https://www.angelaambroz.com/posts/cs50__algorithms/</link><pubDate>Mon, 12 Feb 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/cs50__algorithms/</guid><description>&lt;p>Ah haaa, and now we enter the densest, most bare metal forest of CS50, I AM SO PLEASED.&lt;/p>
&lt;p>Looking at the &lt;a href="https://docs.cs50.net/2018/x/syllabus.html" target="_blank">syllabus&lt;/a>, I see that the future brings much Python and JavaScript - two languages I&amp;rsquo;ve been speaking for a while now - and so I am assuming those weeks will be a breeze. Check back in a month&amp;rsquo;s time to see if that&amp;rsquo;s the case.&lt;/p>
&lt;p>But now! Now it&amp;rsquo;s been a wonderful ride through challenging and informative basic CS topics. This is what I came for! (I also came for data structures and HTTP, which are the next few weeks, woohoo.)&lt;/p>
&lt;hr>
## Week 2: Algorithms
&lt;iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/k4RRi_ntQc8" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen>&lt;/iframe>
&lt;p>This week&amp;rsquo;s topic was algorithms, the varying measures of their speed, and common ones used for sorting integers:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/Insertion_sort" target="_blank">Insertion sort&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/Bubble_sort" target="_blank">Bubble sort&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/Selection_sort" target="_blank">Selection sort&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/Merge_sort" target="_blank">Merge sort&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>On speeds: given that processors have different speeds, there&amp;rsquo;s idiosyncratic noise to computer speed, and blah blah, there is something called big-O notation. Big-O is the number of operations the computer needs to perform to complete an (algorithmic) task.&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;We use big-Θ notation to asymptotically bound the growth of a running time to within constant factors above and below. Sometimes we want to bound from only above. [&amp;hellip;] It would be convenient to have a form of asymptotic notation that means &amp;ldquo;the running time grows at most this much, but it could grow more slowly.&amp;rdquo; We use &amp;ldquo;big-Θ&amp;rdquo; notation for just such occasions.&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>(&lt;a href="https://www.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/big-o-notation" target="_blank">khan academy&lt;/a>)&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;Big O notation is a mathematical notation that describes the limiting behavior of a function when the argument tends towards a particular value or infinity.&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>(&lt;a href="https://en.wikipedia.org/wiki/Big_O_notation" target="_blank">wiki&lt;/a>)&lt;/p>
&lt;p>Normally written as $O(n)$ where $n$ is the size of the task: e.g. the length of the list you want to sort. Big-O is also the &lt;em>worst case scenario&lt;/em>: that is, how long it would take to sort a list of integers if you never got any lucky breaks (as defined by the way the algorithm sorts). It&amp;rsquo;s our upper bound.&lt;/p>
&lt;p>Good big-Os are things like logarithmic algorithms: stuff that, no matter how big of a list you throw at it, won&amp;rsquo;t ever take longer than the log of that list&amp;rsquo;s length.&lt;/p>
&lt;p>Behold now eight different algorithms, eight different speeds:&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/Comparison_computational_complexity.svg/600px-Comparison_computational_complexity.svg.png" alt="big-O" />
&lt;/figure>
&lt;/p>
&lt;p>(&lt;a href="https://en.wikipedia.org/wiki/Big_O_notation#Big_Omega_notation" target="_blank">wiki&lt;/a>)&lt;/p>
&lt;p>There&amp;rsquo;s also a notation for the &lt;em>best case scenario&lt;/em>: omega, $\omega(n)$. If you need to sort a list and it&amp;rsquo;s already, by chance, sorted - you need to only look through it once to be sure, ergo in that case $\omega(1)$.&lt;/p>
&lt;p>And finally, theta - $\theta(n)$ - as the range between the upper and lower bounds.&lt;/p>
&lt;p>Beyond measuring algorithms&amp;rsquo; efficiency, what about what these algorithms are actually doing? Pictures/videos are worth infinity words here, and I really enjoyed these two resources -&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html" target="_blank">Visualizing algorithms&lt;/a> - To watch each sorting algorithm in action.&lt;/li>
&lt;li>&lt;a href="https://www.toptal.com/developers/sorting-algorithms" target="_blank">Sorting Algorithms Animations&lt;/a> - To watch several in action, as they race against each other.
&lt;br>&lt;/li>
&lt;/ol>
&lt;h3 class="relative group">Problem set: &lt;a href="https://docs.cs50.net/2018/x/psets/3/music/music.html" target="_blank">Music&lt;/a>
&lt;div id="problem-set-musichttpsdocscs50net2018xpsets3musicmusichtml" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#problem-set-musichttpsdocscs50net2018xpsets3musicmusichtml" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Expectations&lt;/strong>: This PS didn&amp;rsquo;t ask students to implement any of the algorithms covered in the lecture (which I was expecting). It also didn&amp;rsquo;t explicitly ask for any recursion - another lecture topic - and I didn&amp;rsquo;t (and still don&amp;rsquo;t) see much opportunity to try solving the puzzles with a recursive function.&lt;/li>
&lt;li>&lt;strong>Content&lt;/strong>: This was a lot of fun: converting text to music, via &lt;a href="https://plus.maths.org/content/magical-mathematics-music" target="_blank">magical music math&lt;/a> and how it relates to the wavelengths of each pitch. This spoke to my &lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/20/i_heart_waves/" target="_blank">idiosyncratic love of waves&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Difficulty&lt;/strong>: Quite a bit trickier than earlier weeks, I ended up arriving at the Cognitive Wall - that place where you&amp;rsquo;re just banging your head, making no progress, and some time &lt;em>away&lt;/em> from the problem works miracles. Taking a break helped. Also, I found &lt;a href="http://www.reddit.com/r/cs50/" target="_blank">r/cs50&lt;/a>. :)&lt;/li>
&lt;/ul>
&lt;br>
&lt;hr>
## Week 4: Memory
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/C-memlayout.svg/557px-C-memlayout.svg.png" alt="stack heap" />
&lt;/figure>
&lt;/p>
&lt;p>(&lt;a href="https://commons.wikimedia.org/wiki/File:C-memlayout.svg" target="_blank">wiki&lt;/a>)&lt;/p>
&lt;p>Memory! The stack and the heap! We actually drew it upside down - with the stack at the bottom and the heap at the top. I really enjoyed this lecture, since it started demystifying a lot of stuff - specifically, demystifying the connection between programming variables, values, scope, and functions, and how they&amp;rsquo;re all connected to (i.e. stored in) memory. This was very empowering. We learned about pointers (which are just &lt;a href="https://en.wikipedia.org/wiki/Memory_address" target="_blank">addresses/locations in memory&lt;/a>). Basically, in C, you can:&lt;/p>
&lt;ul>
&lt;li>Initiate some variable, e.g. an integer, and call it &lt;code>x&lt;/code>. When you do this, some space - 4 bytes, specifically - in memory is allocated to an integer called &lt;code>x&lt;/code>.&lt;/li>
&lt;li>Set its value to &lt;code>x=5&lt;/code>. The memory location now holds the value for &lt;code>5&lt;/code>, in binary, written with those 4 bytes.&lt;/li>
&lt;li>Grab its address, &lt;code>&amp;amp;x&lt;/code>. This returns a memory address, written in &lt;a href="https://en.wikipedia.org/wiki/Hexadecimal" target="_blank">hexadecimal&lt;/a> (i.e. base-16 numbering).&lt;/li>
&lt;li>&lt;em>Dereference&lt;/em> it, &lt;code>*x&lt;/code>: that is, access and - if desired - change the value at its memory location. Of course, we could just change &lt;code>x&lt;/code>&amp;rsquo;s value by setting &lt;code>x=1&lt;/code> or whatever, but if we want to swap variable names, or use a second variable in general to reference to &lt;code>x&lt;/code>&amp;rsquo;s memory and make changes there, then that&amp;rsquo;s something pointers are useful for. Here&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/Dereference_operator" target="_blank">the wiki example&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Also exciting to learn about was hexadecimal, dynamic memory allocation (grabbing a piece of memory from the memory heap using &lt;code>malloc()&lt;/code>) and the attendant memory leaks, and the call stack (which totally demystified recursion). Wonderful!&lt;/p>
&lt;h3 class="relative group">Problem set: &lt;a href="https://docs.cs50.net/2018/x/psets/4/pset4.html" target="_blank">Forensics&lt;/a>
&lt;div id="problem-set-forensicshttpsdocscs50net2018xpsets4pset4html" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#problem-set-forensicshttpsdocscs50net2018xpsets4pset4html" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>I&amp;rsquo;ve only just started this PS, which looks daunting - but manageable. The first part - &lt;a href="https://docs.cs50.net/2018/x/psets/4/whodunit/whodunit.html" target="_blank">Whodunit&lt;/a> - had an &lt;em>enormous&lt;/em> amount of info on bitmap file storage, which I ended up finding super interesting, and then it kinda took the training wheels off and was like, &lt;a href="https://xkcd.com/293/" target="_blank">RTFM&lt;/a> - i.e. reading and understanding documentation! Not for the faint of heart! But, like &lt;code>bash&lt;/code> and regular expressions and &lt;a href="https://www.angelaambroz.com/blog/posts/2018/Jan/10/understanding_a_big_wide_codebase/" target="_blank">reading code&lt;/a>, an important meta-skill.&lt;/p>
&lt;hr>
## Conclusion
&lt;p>Alrightie, these two weeks were some of the biggest value add so far. Really excited to keep going! Huzzah!&lt;/p>
&lt;p>A side note: Every time anyone said &lt;code>malloc()&lt;/code>, I would hear Allen Ginsberg&amp;rsquo;s wonderful exclamations from &lt;a href="https://www.poetryfoundation.org/poems/49303/howl" target="_blank">Howl&lt;/a>: &lt;em>&amp;ldquo;Moloch!&amp;rdquo;&lt;/em> Damn Moloch! From the poem:&lt;/p>
&lt;blockquote>
&lt;p>What sphinx of cement and aluminum bashed open their skulls and ate up their brains and imagination?&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Moloch! Solitude! Filth! Ugliness! Ashcans and unobtainable dollars! Children screaming under the stairways! Boys sobbing in armies! Old men weeping in the parks!&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Moloch! Moloch! Nightmare of Moloch! Moloch the loveless! Mental Moloch! Moloch the heavy judger of men!&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Moloch the incomprehensible prison! Moloch the crossbone soulless jailhouse and Congress of sorrows! Moloch whose buildings are judgment! Moloch the vast stone of war! Moloch the stunned governments!&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Moloch whose mind is pure machinery! Moloch whose blood is running money! Moloch whose fingers are ten armies! Moloch whose breast is a cannibal dynamo! Moloch whose ear is a smoking tomb!&lt;/p>
&lt;/blockquote>
&lt;p>(&lt;a href="https://www.poetryfoundation.org/poems/49303/howl" target="_blank">source&lt;/a>)&lt;/p></description></item><item><title>Full stack Python- My first Flask app</title><link>https://www.angelaambroz.com/posts/full_stack_python_my_first_flask_app/</link><pubDate>Mon, 05 Feb 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/full_stack_python_my_first_flask_app/</guid><description>&lt;p>I&amp;rsquo;m a big fan of using the internet to share meaningful life events like weddings and births and so on. But I&amp;rsquo;ve been growing increasingly uncomfortable with using social media platforms like Facebook or Twitter for that - those platforms aren&amp;rsquo;t designed, really, for optimizing real, human connection; they&amp;rsquo;re designed to monetize human attention span by selling it to advertisers.&lt;/p>
&lt;p>They&amp;rsquo;re meant to drive &amp;ldquo;engagement&amp;rdquo; (our time, our attention), which is the product that they sell to their clients (the advertising industry). (Incidentally, I&amp;rsquo;m reading Tim Wu&amp;rsquo;s &lt;a href="https://www.goodreads.com/book/show/28503628-the-attention-merchants" target="_blank">The Attention Merchants&lt;/a>, which talks about this and is v. good.) I especially don&amp;rsquo;t feel comfortable sharing stuff about kids/babies; it&amp;rsquo;s not giving their individual privacy a chance, it offers them up to the advertisers at a very young age. As minors, I feel that we should be protecting them from this stuff, not normalizing it and binding their childhoods/sense of self (?) to it. There&amp;rsquo;s &lt;a href="https://stallman.org/facebook.html" target="_blank">lots of other reasons not to use these platforms&lt;/a>.&lt;/p>
&lt;p>There are some off-the-shelf tools to address this - the problem of sharing meaningful, but private, life events with family and close friends, unmediated by advertisers and a profit motive - e.g. &lt;a href="https://www.23snaps.com/" target="_blank">23snaps&lt;/a> or &lt;a href="https://www.theknot.com/content/wedding-website-passwords" target="_blank">TheKnot&amp;rsquo;s password-protected wedding websites&lt;/a>?&lt;/p>
&lt;p>But, again, it&amp;rsquo;s not much control and I&amp;rsquo;m not sure it really &lt;em>is&lt;/em> a good alternative: e.g. I don&amp;rsquo;t know where the data is or how it&amp;rsquo;s used - whether it&amp;rsquo;s ultimately sold to those data aggregation/middleman agencies or used in machine learning work.&lt;/p>
&lt;p>Side note: I used to work on household surveys in India (e.g. &lt;a href="https://www.povertyactionlab.org/evaluation/measuring-impact-microfinance-hyderabad-india" target="_blank">this&lt;/a>), and it was important that consent - to be in the study, to be interviewed by us - was made a very explicit step before any survey began. Our surveyors read the consent form in Telugu, any and all questions from the potential respondent were answered, and only when they explicitly said it was okay would we enter to begin the survey. Right now, our &amp;ldquo;consent to be researched on&amp;rdquo; (i.e. included in A/B tests, have our data used in training machine learning algorithms) is buried in Terms of Service and End User License Agreements that &lt;a href="https://www.theguardian.com/technology/2017/mar/03/terms-of-service-online-contracts-fine-print" target="_blank">no one reads&lt;/a>. These TOSs can change, and, de facto, they&amp;rsquo;re legal &lt;a href="https://en.wikipedia.org/wiki/Cover_your_ass" target="_blank">CYA&lt;/a> for carte blanche data use.&lt;/p>
&lt;p>But I digress.&lt;/p>
&lt;p>My conclusion was to make something &amp;ldquo;in house&amp;rdquo;: where I pay for the server space (instead of having advertisers pay for it), I keep it password protected, and basically the onus is on me to make sure it doesn&amp;rsquo;t get used for bad purposes. Plus, learning how to make a password-protected website is a useful skill! So here&amp;rsquo;s a blog post about that journey.&lt;/p>
&lt;h2 class="relative group">Specs
&lt;div id="specs" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#specs" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ol>
&lt;li>A website&lt;/li>
&lt;li>That is password-protected&lt;/li>
&lt;li>And isn&amp;rsquo;t hideous&lt;/li>
&lt;li>And is in Python&lt;/li>
&lt;li>And hopefully won&amp;rsquo;t get hacked by bad actors :P&lt;/li>
&lt;/ol>
&lt;p>So this was going to be my first foray into &lt;a href="https://medium.com/coderbyte/a-guide-to-becoming-a-full-stack-developer-in-2017-5c3c08a1600c" target="_blank">&amp;ldquo;real&amp;rdquo; full-stack web development&lt;/a>. Things like &lt;a href="https://www.angelaambroz.com/" target="_blank">this&lt;/a> website are static: they use CSS, HTML, and a bit of JavaScript. There&amp;rsquo;s no need for a &amp;ldquo;backend&amp;rdquo; - there&amp;rsquo;s no users, and therefore no database.&lt;/p>
&lt;p>I had a bunch of questions of how this would work: how do I set up a database backend on a remote server? How do I store passwords? (Do I need to learn more about encryption?) Where do I put it (which webhost is good and cheap and &lt;a href="https://www.fastcompany.com/3041434/why-godaddy-is-finally-trying-to-repairing-its-sexist-reputation" target="_blank">not sexist&lt;/a>?) and how do I use a custom domain that I already bought and paid for? I was hazy on all this stuff.&lt;/p>
&lt;h2 class="relative group">Flask, I choose you!
&lt;div id="flask-i-choose-you" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#flask-i-choose-you" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Full-stack development in Python is dominated by two popular frameworks: &lt;a href="https://www.djangoproject.com/" target="_blank">Django&lt;/a> and &lt;a href="http://flask.pocoo.org/" target="_blank">Flask&lt;/a>. Django has a reputation for being big and comprehensive and coming with lots of bells and whistles, while Flask is meant to be more minimalist. Since I wasn&amp;rsquo;t building an industry-level app, I figured Flask would be fine. (I also liked the Horn of Gondor logo, heh.)&lt;/p>
&lt;h2 class="relative group">Finding the right tutorial
&lt;div id="finding-the-right-tutorial" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#finding-the-right-tutorial" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://www.datacommunitydc.org/blog/2014/02/flask-mega-meta-tutorial-data-scientists" target="_blank">Flask Mega Meta Tutorial for Data Scientists&lt;/a> - To find the tutorial that&amp;rsquo;s right for me!&lt;/li>
&lt;li>&lt;a href="https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world" target="_blank">The Flask Mega Tutorial&lt;/a> - The tutorial I chose.&lt;/li>
&lt;/ul>
&lt;p>Honestly, the hardest thing on a learning journey is usually finding a compelling project. Once you have one of those, one tutorial is about as good as another. But I poked around the &lt;a href="http://www.datacommunitydc.org/blog/2014/02/flask-mega-meta-tutorial-data-scientists" target="_blank">metalist&lt;/a> and was ultimately quite happy with &lt;a href="https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world" target="_blank">Miguel Grinberg&amp;rsquo;s &amp;ldquo;mega&amp;rdquo; tutorial&lt;/a>, which was modular and comprehensive.&lt;/p>
&lt;p>In Miguel&amp;rsquo;s tutorial, the project is building a social network-style app: there are users who make posts, and you need a database to keep track of people&amp;rsquo;s logins, their posts, and so on. I ignored the specifics of the project and ported stuff over to my interest: making a private family website. I really recommend Miguel&amp;rsquo;s tutorial (and won&amp;rsquo;t attempt to re-do it here!).&lt;/p>
&lt;h2 class="relative group">Stuff I learned along the way
&lt;div id="stuff-i-learned-along-the-way" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#stuff-i-learned-along-the-way" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;h3 class="relative group">The model-view-controller pattern
&lt;div id="the-model-view-controller-pattern" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-model-view-controller-pattern" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Although I attended a &lt;a href="http://www.railsbridge.org/" target="_blank">RailsBridge&lt;/a> weekend a long time ago, it didn&amp;rsquo;t really meet me where I was. A lot of time was focused on getting our environments set up and basic programming. I think it&amp;rsquo;s &lt;em>great&lt;/em> for women just starting out in tech, since web development is a good career path (especially for people transitioning in) and RailsBridge assumes zero programming experience. It&amp;rsquo;s awesome to get your feet wet.&lt;/p>
&lt;p>But I had only one big takeaway from RailsBridge, and that was that there was something called the &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" target="_blank">model-view-controller (MVC) pattern&lt;/a> out there, and this was important for web frameworks. I was still kinda hazy on what was what (is the database the controller? or the model?): working through the mega-tutorial and building my first Flask app, though, really clarified stuff. And what a beautiful pattern it is!&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/MVC-Process.svg/545px-MVC-Process.svg.png" alt="MVC, wiki" />
&lt;/figure>
&lt;/p>
&lt;p>(&lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" target="_blank">source&lt;/a>)&lt;/p>
&lt;p>My current understanding of the MVC is:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Model&lt;/strong>: The abstractions which your web app expects, and which will be turned into data; in Flask, these were abstracted into Python classes. e.g. A &lt;code>User&lt;/code>, a &lt;code>Post&lt;/code>, a &lt;code>Status&lt;/code> or &lt;code>Photo&lt;/code> or whatever. I just needed a &lt;code>User&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Views&lt;/strong>: The actual HTML/CSS that your web app presents to users.&lt;/li>
&lt;li>&lt;strong>Controller&lt;/strong>: The logic which underlies how the model and views (and the user and your website) interact. For example, some &lt;code>Users&lt;/code> might get certain views (HTML pages), depending on whether they&amp;rsquo;re logged in or not.&lt;/li>
&lt;/ul>
&lt;p>For the Flask app, my MVC looked like this (as described in Miguel Grinberg&amp;rsquo;s &lt;a href="https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world" target="_blank">tutorial&lt;/a>):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">- README.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- my_app.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- config.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- my_app.db
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">- my_app/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - forms.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - models.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - routes.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - templates/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> - a bunch of sweet html
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Where &lt;code>my_app.py&lt;/code> just &lt;code>imports&lt;/code> my web app (the &lt;code>my_app/&lt;/code> folder) and makes it ready for running locally/on a server, &lt;code>templates/&lt;/code> is where all my &lt;strong>views&lt;/strong> are (a bunch of &lt;code>.html&lt;/code> files for, e.g., the index, login/logout pages, private photo gallery, and other stuff), &lt;code>routes.py&lt;/code> is my &lt;strong>controller&lt;/strong> (deciding how and when certain &lt;strong>views&lt;/strong> are shown), &lt;code>forms.py&lt;/code> separates out the user forms (e.g. the login form template, etc), and &lt;code>models.py&lt;/code> defines a couple Python classes (&lt;code>User&lt;/code>).&lt;/p>
&lt;p>The thing I like about this pattern, and Flask, is:&lt;/p>
&lt;ul>
&lt;li>All the HTML/CSS beautifying - and I think I&amp;rsquo;ll use &lt;a href="https://getbootstrap.com/" target="_blank">Bootstrap&lt;/a> to quickly make it more pretty - is separated out into its own front end/views space.&lt;/li>
&lt;li>Separating out the logic (&lt;code>routes.py&lt;/code>) from the abstractions of data your web app expects (&lt;code>models.py&lt;/code>) was also helpful. Specifically, thinking about &lt;em>what abstractions are appropriate for your web app&lt;/em>. I&amp;rsquo;m making a plain vanilla &amp;ldquo;my website will have users!&amp;rdquo; web app, but I can imagine other, cool extensions: a TODO list (&lt;code>User&lt;/code>, &lt;code>Task&lt;/code>), a movie review website (&lt;code>User&lt;/code>, &lt;code>Movie&lt;/code>, &lt;code>Actor&lt;/code>, &lt;code>Director&lt;/code>, &lt;code>Theater&lt;/code>), etc.&lt;/li>
&lt;li>Flask had a &lt;em>lot&lt;/em> of nice off-the-shelf stuff for common patterns (&lt;a href="http://exploreflask.com/en/latest/users.html" target="_blank">docs&lt;/a>): e.g. having users and logging them in via a web form. All of those steps ((1) having users, (2) logging them in, (3) via a web form) had pre-baked stuff that just needed to be tinkered with, e.g. from my &lt;code>models.py&lt;/code>:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">werkzeug.security&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">generate_password_hash&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">check_password_hash&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">flask_login&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UserMixin&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">my_app&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">login&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">UserMixin&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Model&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Column&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Integer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">primary_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">email&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Column&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">120&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">index&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">unique&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">password_hash&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Column&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">128&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">posts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">relationship&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Post&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">backref&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;author&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">lazy&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;dynamic&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">set_password&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">password&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">password_hash&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">generate_password_hash&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">password&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">check_password&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">password&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">check_password_hash&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">password_hash&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">password&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__repr__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s1">&amp;#39;&amp;lt;User &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s1">&amp;gt;&amp;#39;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">email&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>All that stuff - the &lt;code>UserMixin&lt;/code> and &lt;code>werkzeug.security&lt;/code> stuff for generating secure passwords (without me, as the webdev, ever seeing them in plaintext), was very cool.&lt;/p>
&lt;h3 class="relative group">&lt;code>Jinja&lt;/code> HTML templating
&lt;div id="jinja-html-templating" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#jinja-html-templating" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>From the &lt;a href="http://jinja.pocoo.org/" target="_blank">docs&lt;/a>:&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;Jinja2 is a full featured template engine for Python. It has full unicode support, an optional integrated sandboxed execution environment, widely used and BSD licensed.&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>For my family web app, I used Jinja to create my &lt;strong>views&lt;/strong> - i.e. my HTML files. Jinja allows you to create HTML that dynamically responds to stuff - e.g. it can access Python variables and, depending on them, display this or that &lt;code>&amp;lt;div&amp;gt;&lt;/code> tag, etc. This is distinct from, say, writing JavaScript that dynamically responds to stuff (which would be another way, I suppose, to do all this). My &lt;code>templates/&lt;/code> folder has a bunch of Jinja-fied HTML, but the important one is &lt;code>base.html&lt;/code> -&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {% if user %}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Welcome, {{ user.username }}&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {% else %}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Welcome!&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {% endif %}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {% block content %}{% endblock %}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">body&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">html&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The money bits above are the curly braces stuff (e.g. &lt;code>{% if user %}&lt;/code> in between &lt;code>&amp;lt;head&amp;gt;...&amp;lt;/head&amp;gt;&lt;/code>). That&amp;rsquo;s the Jinja. &lt;code>user&lt;/code> is a Python variable defined elsewhere in the project, it&amp;rsquo;s one of our &lt;strong>models&lt;/strong>, and - in &lt;code>base.html&lt;/code> - we&amp;rsquo;re going to modify how the the &lt;code>&amp;lt;head&amp;gt;&lt;/code> attribute will look, based on whether that &lt;code>user&lt;/code> has signed in or not.&lt;/p>
&lt;p>Another nice thing about Jinja is that, after setting up the general look and feel of your website in &lt;code>base.html&lt;/code>, you can create more &lt;code>*.html&lt;/code> files that &amp;ldquo;inherit&amp;rdquo; that look and feel. Rather than copy-pasting the same header, navigation bar, or CSS link, you can just stick that all in your &lt;code>base.html&lt;/code> and then do something like this for your &lt;code>index.html&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">{% extends &amp;#34;base.html&amp;#34; %}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{% block content %}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h1&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Hi, {{ current_user.email }}! Now you&amp;#39;re in /index - wow!&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h1&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Lorem ipsem blah blah&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{% endblock %}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In the above, &lt;code>index.html&lt;/code> inherits from &lt;code>base.html&lt;/code> (&lt;code>{% extends &amp;quot;base.html&amp;quot; %}&lt;/code>) and then adds its own content (&lt;code>{% block content }&lt;/code>).&lt;/p>
&lt;p>Like &lt;code>pandas&lt;/code> or regular expressions then, Jinja has its own special, &lt;em>additional&lt;/em> syntax you need to learn - on top of regular old Python. All those curly braces! Why! But building a Flask app helped a lot in terms of learning it. (FWIW Pelican uses Jinja as well. I wish I had &lt;a href="http://www.angelaambroz.com/blog/posts/2017/Nov/30/hello_pelican/" target="_blank">known more about that back in November&lt;/a>!)&lt;/p>
&lt;h3 class="relative group">How to put it on the internet?
&lt;div id="how-to-put-it-on-the-internet" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-to-put-it-on-the-internet" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Once I got a small Flask app running locally, but &lt;em>before&lt;/em> making the views non-hideous, I wanted to figure out how to run it on a remote server. I didn&amp;rsquo;t want to invest a ton of front end time before confirming that I could figure out the back end. So: how to actually put this ugly app on the internet?&lt;/p>
&lt;p>Running a Flask app locally is as simple as:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">FLASK_APP&lt;/span>&lt;span class="o">=&lt;/span>path/to/my_app/my_app.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">flask run
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This launches a local server and runs your web app on some port (e.g. &lt;code>8000&lt;/code>) in &lt;code>localhost&lt;/code>. You just navigate your web browser (Chrome/Firefox/Safari) to &lt;code>localhost:8000&lt;/code> and voila - you should see your app. You can just &lt;code>CTRL+C&lt;/code> the bash console that&amp;rsquo;s running the server to close everything.&lt;/p>
&lt;p>But how does this work on the actual, real internet? This was where &lt;a href="https://www.pythonanywhere.com" target="_blank">PythonAnywhere&lt;/a> came in.&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;PythonAnywhere is an online Integrated Development Environment (IDE) and Web hosting service based on the Python programming language.[1] It provides in-browser access to server-based Python and Bash Command-line interfaces, along with a code editor with Syntax highlighting. Program files can be transferred to and from the service using the user&amp;rsquo;s browser. Web applications hosted by the service can be written using any WSGI-based application framework.&amp;rdquo;&lt;/em>
(&lt;a href="https://en.wikipedia.org/wiki/PythonAnywhere" target="_blank">wiki&lt;/a>)&lt;/p>
&lt;/blockquote>
&lt;p>What&amp;rsquo;s nice about PythonAnywhere was that it came with a bunch of &amp;ldquo;pythonista&amp;rdquo; stuff included: you can easily launch bash consoles or Jupyter notebooks or set up MySQL databases, a bunch of Python packages are pre-installed, setting up virtual environments is super easy, you can &lt;code>git clone&lt;/code> stuff into your PythonAnywhere account, you can also drag + drop files (like a &lt;code>favicon&lt;/code>!), &lt;em>and&lt;/em> - most easily - you can launch a Django or Flask web app pretty painlessly. And they&amp;rsquo;ll host it! And it&amp;rsquo;s pretty cheap ($5/month)! And you can DNS resolve it to your custom domain! So nice.&lt;/p>
&lt;h3 class="relative group">What is WSGI?
&lt;div id="what-is-wsgi" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#what-is-wsgi" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>But why couldn&amp;rsquo;t I just buy some server space somewhere and run &lt;code>flask run&lt;/code>?&lt;/p>
&lt;p>If you want to run Python web apps (Django/Flask/whatever), you need to get Python (and Flask, etc.) installed on a server. So how do you do that? This is where WSGI (Web Server Gateway Interface) comes in. This &lt;a href="https://www.fullstackpython.com/wsgi-servers.html" target="_blank">article by Full Stack Python&lt;/a> was very informative:&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;A traditional web server does not understand or have any way to run Python applications. In the late 1990s, a developer named Grisha Trubetskoy came up with an Apache module called mod_python to execute arbitrary Python code. For several years in the late 1990s and early 2000s, Apache configured with mod_python ran most Python web applications.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>However, mod_python wasn&amp;rsquo;t a standard specification. It was just an implementation that allowed Python code to run on a server. As mod_python&amp;rsquo;s development stalled and security vulnerabilities were discovered there was recognition by the community that a consistent way to execute Python code for web applications was needed.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>Therefore the Python community came up with WSGI as a standard interface that modules and containers could implement. WSGI is now the accepted approach for running Python web applications.&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>Incidentally, linked from the Full Stack Python post, here&amp;rsquo;s the &lt;a href="https://grisha.org/blog/2013/10/25/mod-python-the-long-story/" target="_blank">super interesting story of WSGI&amp;rsquo;s predecessor, &lt;code>mod_python&lt;/code>, and how it was developed, as told by its creator&lt;/a>.&lt;/p>
&lt;h2 class="relative group">Voila!
&lt;div id="voila" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#voila" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>And that&amp;rsquo;s it! I&amp;rsquo;ve really enjoyed beginning my full stack journey, and getting a Flask app up and running. I&amp;rsquo;m not going to link it because - well - it&amp;rsquo;s hideous and has no CSS or content right now. But now that I got the back end part sorted, it&amp;rsquo;s time for front end!&lt;/p></description></item><item><title>A few of my favorite pytest</title><link>https://www.angelaambroz.com/posts/a_few_of_my_favorite_pytest_things/</link><pubDate>Wed, 24 Jan 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/a_few_of_my_favorite_pytest_things/</guid><description>&lt;p>YAZZZZ. I just raised my Python points over 9,000!&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://media.giphy.com/media/xQCDGWV6FV2E0/giphy.gif" alt="raaaaah" />
&lt;/figure>
&lt;/p>
&lt;p>Sort of. I learned how to do something in &lt;code>pytest&lt;/code> that blew my mind: creating fake attributes and methods of other Python objects. This meant getting better at understanding how modules and objects &lt;em>work&lt;/em>. It was, mwah, so cool. But first, let&amp;rsquo;s talk &lt;code>pytest&lt;/code> and why-test.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Why test?
&lt;div id="why-test" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#why-test" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This was &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/09/git_history_is_written_by_the_victors/" target="_blank">another culture shock&lt;/a> about moving into tech: &lt;strong>unit tests&lt;/strong>. In academia economica, you write a bunch of Stata code (&lt;code>.do&lt;/code> files!), run a bunch of regressions, and hope it doesn&amp;rsquo;t break and consider yourself replicable. But, ah ha, in tech world, your codebases are big, pieces of code interact in complicated ways, and it gets hard to hold it all in your head at once.&lt;/p>
&lt;p>So you unit test!&lt;/p>
&lt;p>The benefit of testing, as I see it, is that - as your codebase grows &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/10/understanding_a_big_wide_codebase/" target="_blank">larger and more complex&lt;/a> - it becomes harder and harder to know if any one change will break something else. The interactions and inter-dependencies get too complex. Often, multiple developers are working on different parts of the same, overall code. Unit tests, especially if they&amp;rsquo;re small and discrete, can help. You break things down into small packets and make sure each joint in the pipe is working. They also force you to write small, discrete functions, and - by testing constantly - you can see if a small change on module A will lead to a break in module B, etc.&lt;/p>
&lt;p>Then there&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/Test-driven_development" target="_blank">test-driven development (TDD)&lt;/a>, where the tests are written first and the code is written afterwards, constantly revised &lt;em>until&lt;/em> the tests pass. I like this idea, but haven&amp;rsquo;t really done it (yet!).&lt;/p>
&lt;p>My current practice is to use tests as a way to &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/10/understanding_a_big_wide_codebase/" target="_blank">get to know a codebase&lt;/a>: I&amp;rsquo;ll write new ones for code that isn&amp;rsquo;t covered, and I&amp;rsquo;ll tinker with old ones to see how they work.&lt;/p>
&lt;h2 class="relative group">A great video
&lt;div id="a-great-video" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#a-great-video" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I want to highlight &lt;a href="https://www.youtube.com/watch?v=FxSsnHeWQBY" target="_blank">this talk by Ned Batchelder at PyCon 2014&lt;/a>, since it really informed the way I think about testing. The one thing that struck me that &lt;a href="https://nedbatchelder.com/" target="_blank">Ned&lt;/a> said was, basically, treat your tests with the same respect and reverence as your code. Your tests don&amp;rsquo;t &lt;em>need&lt;/em> to be repetitive, non-DRY, ugly hunks of semi-identical tests. They can have objects. They can have good structure. &lt;code>pytest&lt;/code> can help you write these tests in beautiful ways.&lt;/p>
&lt;h2 class="relative group">A great essay
&lt;div id="a-great-essay" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#a-great-essay" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://www.facebook.com/notes/kent-beck/one-bite-at-a-time-partitioning-complexity/1716882961677894/?__s=igzvxemrwyh2rgdqkf1t" target="_blank">This post by Kent Beck&lt;/a> is also great at thinking through the how and why to test.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">&lt;code>pytest&lt;/code> (specifically, faking stuff in &lt;code>pytest&lt;/code>)
&lt;div id="pytest-specifically-faking-stuff-in-pytest" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#pytest-specifically-faking-stuff-in-pytest" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Python has &lt;a href="https://docs.python.org/2/library/unittest.html" target="_blank">&lt;code>unittest&lt;/code>&lt;/a> built into the standard library (i.e. comes with Python), but I&amp;rsquo;ve been digging &lt;a href="https://docs.pytest.org/en/latest/" target="_blank">&lt;code>pytest&lt;/code>&lt;/a>. I reeeally like &lt;code>pytest&lt;/code>. It has lots of very handy stuff either built-in or as easy &lt;code>pip&lt;/code> installable extensions. I&amp;rsquo;ll talk one the SUPER COOL thing I learned about: &lt;strong>fixtures and monkeypatching!&lt;/strong>&lt;/p>
&lt;p>One of the challenges of unit testing data-driven code (like a data science service, or ETL pipeline) is that it relies on external dependencies (e.g. a database, an API, a Kafka stream). To address this, we can use a monkeypatch fixture.&lt;/p>
&lt;p>Fixtures (&lt;a href="https://docs.pytest.org/en/latest/fixture.html" target="_blank">docs&lt;/a>) allow you to pre-define baseline &amp;ldquo;states of the world&amp;rdquo; that you then test your modules against. They are related to the &lt;a href="https://docs.pytest.org/en/latest/xunit_setup.html" target="_blank">set-up/tear-down&lt;/a> pattern where you set up, for example, a &amp;ldquo;fake&amp;rdquo; database object or a &amp;ldquo;fake&amp;rdquo; Kafka stream object, test your code with that, and then tear down the fake object. The convenient part of &lt;code>pytest&lt;/code>’s fixtures is that setting up and tearing down is abstracted away from you. You just use the &lt;code>@pytest.fixture&lt;/code> decorator in your &lt;code>test_module.py&lt;/code> file, and &lt;code>pytest&lt;/code> handles it for you.&lt;/p>
&lt;p>Monkeypatching (&lt;a href="https://docs.pytest.org/en/latest/_modules/_pytest/monkeypatch.html" target="_blank">docs&lt;/a>) is one such fixture. It allows you to directly (and temporarily) modify existing modules, both from your own project as well as external libraries. For example, you could monkeypatch the &lt;code>requests&lt;/code> library such that &lt;code>requests.get()&lt;/code> always returns a specific string - but only in the context of your tests. So you don&amp;rsquo;t have to worry about sullying your copy of &lt;code>requests&lt;/code>, nor do you have to deal with the pain of setting it all up and tearing it all down.&lt;/p>
&lt;h2 class="relative group">Example: Fixing ye olde Odo bot
&lt;div id="example-fixing-ye-olde-odo-bot" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#example-fixing-ye-olde-odo-bot" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>My beloved &lt;a href="https://github.com/hks-epod/odo-bot/" target="_blank">odo-bot&lt;/a> was a Slackbot I built, long ago, at my &lt;a href="https://epod.cid.harvard.edu/" target="_blank">old gig&lt;/a>. &lt;code>odo-bot&lt;/code> is early days Python for me, so forgive me the numerous obvious sins. If I re-wrote &lt;code>odo-bot&lt;/code> now (DON&amp;rsquo;T TEMPT ME), I&amp;rsquo;d definitely include tests. For now, let&amp;rsquo;s write a little unit test for one of his functions, &lt;code>Inspiration()&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">Inspiration&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">event&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> A function to provide amusement and inspiration.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> For now, pulls from Reddit&amp;#39;s API and pulls a random top-rated post/image/URL.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;http://www.reddit.com/r/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">random&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">choice&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">SUBREDDITS&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/top.json?t=month&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">inspire&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;I have no inspiration for you now.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;data&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="s1">&amp;#39;children&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="s1">&amp;#39;data&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">inspire&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Try this: &lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2"> &amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">reddit&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;permalink&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Er, re-writing this old function so that it&amp;#39;s not directly calling the Slack API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># sc.api_call(&amp;#34;chat.postMessage&amp;#34;, channel=event[&amp;#39;channel&amp;#39;], text=inspire, as_user=True)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">inspire&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(&lt;a href="https://github.com/hks-epod/odo-bot/blob/master/odo.py" target="_blank">source&lt;/a>)&lt;/p>
&lt;p>Ack! What a mess!&lt;/p>
&lt;p>Anyway, the tldr on this function is that it takes an &lt;code>event&lt;/code> - which is someone on Slack talking to Odo - and returns some &amp;ldquo;inspiring&amp;rdquo; Reddit post. What in the Lord? I don&amp;rsquo;t even remember why I wrote this. What &lt;code>SUBREDDITS&lt;/code>? Why are they global vars? Why did I think to put &lt;code>sc.api_call()&lt;/code> in scope?! Oof.&lt;/p>
&lt;p>Well, anyway. The core of this function is that it&amp;rsquo;s calling the Reddit API (&lt;code>request.get()&lt;/code>), parsing the response (&lt;code>if response.status_code&lt;/code>, &lt;code>response.json()&lt;/code>), and then posting it to the Slack API (&lt;code>sc.api_call()&lt;/code>). The core of this function is parsing Reddit API responses correctly; that&amp;rsquo;s what we want to test. But we may not want to test it by making &lt;em>actual&lt;/em> API calls - this would waste our rate limits there. Similarly, we may not want to post test responses to our Slack API. Indeed, we want to isolate things to just testing the core functionality and removing any external dependencies.&lt;/p>
&lt;p>&lt;code>pytest&lt;/code>&amp;rsquo;s monkeypatching can help us!&lt;/p>
&lt;p>We see that &lt;code>response = requests.get()&lt;/code> is the important bit. This returns a &lt;code>requests.Response&lt;/code> object, which has different attributes and methods (&lt;a href="http://docs.python-requests.org/en/master/api/#requests.Response" target="_blank">docs&lt;/a>). We want to somehow mimic the &lt;code>requests.Response.status_code&lt;/code> as well as &lt;code>requests.Response.json()&lt;/code>. However, while &lt;code>.status_code&lt;/code> is a settable attribute, &lt;code>.json()&lt;/code> works on &lt;code>requests.Response.text&lt;/code>, which is &lt;em>not&lt;/em> settable. Also, &lt;code>requests.get()&lt;/code> will call the API; so if we monkeypatch the downstream stuff that&amp;rsquo;s done to the &lt;code>Response()&lt;/code> object (like &lt;code>.text&lt;/code>, &lt;code>.json()&lt;/code>, &lt;code>.status_code&lt;/code>), we&amp;rsquo;ll still be hitting the Reddit API - and bumping up against our rate limit. So let&amp;rsquo;s monkeypatch &lt;code>.get()&lt;/code> itself and return a FAKE RESPONSE OBJECT (aaaah).&lt;/p>
&lt;p>We can do this from within our testing function, &lt;code>test_Inspiration()&lt;/code>, itself. We temporarily modify &lt;code>requests&lt;/code> to do what you want it to for the duration of the test:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_Inspiration&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">monkeypatch&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># The monkeypatch function is defined within the larger test of the function&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">fake_get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_url&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># OMG I know this looks bad, but I think it&amp;#39;s okay...!&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">class&lt;/span> &lt;span class="nc">Fake_Response&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">object&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">200&lt;/span> &lt;span class="c1"># our fake responses are always OK! yay&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># some fake data, who cares, just gotta make&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># sure the structure is the same as Reddit&amp;#39;s actual API responses&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> {&amp;#34;data&amp;#34;: {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;children&amp;#34;: [{
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;data&amp;#34;: {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;permalink&amp;#34;: &amp;#34;some_reddit_link&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> }]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Faking the requests.Response.json() method&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">json&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">loads&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Fake_Response&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">monkeypatch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setattr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">requests&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;get&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">fake_get&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fake_event&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;channel&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;nowhere&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">Inspiration&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fake_event&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;Try this: &lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2"> http://www.reddit.com/r/some_reddit_link&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The way this works is:&lt;/p>
&lt;ol>
&lt;li>You define your testing function, &lt;code>test_Inspiration()&lt;/code>. Make sure to include &lt;code>monkeypatch&lt;/code> as one of your arguments.&lt;/li>
&lt;li>&lt;em>Within that&lt;/em>, you define your mock object or function, &lt;code>Fake_Response()&lt;/code>. This is the function that will temporarily replace the function/attribute/object you are monkeypatching (in our case, &lt;code>requests.get()&lt;/code>).&lt;/li>
&lt;li>Use &lt;code>monkeypatch.setattr(obj, name, value, raising=True)&lt;/code> to temporarily make the object&amp;rsquo;s method (&lt;code>request.get()&lt;/code>) return something else (&lt;code>Fake_Response()&lt;/code>, instead of &lt;code>requests.Response()&lt;/code>). Here&amp;rsquo;s monkeypatch&amp;rsquo;s &lt;a href="https://docs.pytest.org/en/latest/_modules/_pytest/monkeypatch.html" target="_blank">source&lt;/a>.&lt;/li>
&lt;li>Proceed with the test, calling &lt;code>Inspiration(fake_event)&lt;/code>, as usual.&lt;/li>
&lt;/ol>
&lt;p>What I &lt;em>think&lt;/em> happens is that &lt;code>pytest&lt;/code> will catch and parse &lt;code>monkeypatch&lt;/code> when it looks for &lt;code>test_*&lt;/code> functions in your &lt;code>test_*.py&lt;/code>. Here&amp;rsquo;s the &lt;a href="https://docs.pytest.org/en/latest/monkeypatch.html" target="_blank">official tutorial&lt;/a>, similar to the above.&lt;/p></description></item><item><title>Gamifying art</title><link>https://www.angelaambroz.com/posts/gamifying_art/</link><pubDate>Mon, 22 Jan 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/gamifying_art/</guid><description>&lt;p>Lately, I&amp;rsquo;ve been working on art. Specifically, I&amp;rsquo;ve been trying to get better at figure drawing, while also exploring watercolors and portraits. For the former, my two current gurus are:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://www.amazon.com/Natural-Way-Draw-Working-Study/dp/0395530075" target="_blank">Kimon Nicolaides&amp;rsquo;s &lt;em>The Natural Way to Draw: A Working Plan for Art Study&lt;/em>&lt;/a>, which is salty and dated, kinda like &lt;a href="https://learnpythonthehardway.org/" target="_blank">&lt;em>* the Hard Way&lt;/em>&lt;/a>. Very &amp;ldquo;no pain no gain NOW GIVE ME THREE HOURS OF BORING CONTOUR DRAWINGS, PRIVATE!&amp;rdquo;.&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/channel/UClM2LuQ1q5WEc23462tQzBg" target="_blank">Stan Prokopenko&amp;rsquo;s YouTube tutorials&lt;/a>, which are Nicolaides minus pain and a lot more fun. Also YouTube!&lt;/li>
&lt;/ol>
&lt;p>This means I need a constant stream of images for ideally-daily gesture drawing practice. For now, I&amp;rsquo;m using &lt;a href="https://www.quickposes.com/en" target="_blank">quickposes.com&lt;/a> and &lt;a href="https://line-of-action.com/practice-tools/figure-drawing/" target="_blank">Line of Action&lt;/a>. I like Line of Action especially, since it offers both fixed-time poses and a &amp;ldquo;class&amp;rdquo; setting - which starts with quick poses (30 seconds each) and slows down to eventual 5- and 10-minute poses. Also, the images are a lot more, er, tasteful.&lt;/p>
&lt;p>I feel like I&amp;rsquo;m already seeing improvement. Anyway, it&amp;rsquo;s fun! One of my big TODO side projects is supporting this hobby with some bot helpers, e.g. a command line utility to keep track of my progress and find pics and so on.&lt;/p>
&lt;p>For now, I&amp;rsquo;ve also been thinking of how to do this whole thing.&lt;/p>
&lt;hr>
&lt;p>&lt;span class="caption">30 second gestures, Conte black pencil&lt;/span>&lt;/p>
&lt;h1 class="relative group">Acknowledging the reptilian brain, addicted to a screen
&lt;div id="acknowledging-the-reptilian-brain-addicted-to-a-screen" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#acknowledging-the-reptilian-brain-addicted-to-a-screen" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>Social media and modern apps are designed to be addictive. So we can learn from them! I want to make drawing an addiction. One way to build addiction is &lt;strong>random bursts of dopamine&lt;/strong> - that little red notification alert, mmm. So nice. When will it come? Another powerful thing is &lt;strong>gamification of inputs (time spent drawing)&lt;/strong> and the &lt;strong>feeling of progress on outputs (drawings not sucking as much)&lt;/strong>. Finally, as &lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/17/how_i_read/" target="_blank">with Goodreads&lt;/a>, &lt;strong>ego/social performance&lt;/strong> are important motivators too (alas). Finally, I know I should &lt;strong>automate&lt;/strong> as much as possible, reducing any friction to starting my drawing day (or gym visit, or chores). If I can get myself going, I can stick with it more.&lt;/p>
&lt;h2 class="relative group">Random bursts of dopamine
&lt;div id="random-bursts-of-dopamine" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#random-bursts-of-dopamine" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Because I live in, well, 21st century America, I&amp;rsquo;m addicted to consuming. So I&amp;rsquo;ve subscribed to &lt;a href="http://www.artsnacks.co/" target="_blank">ArtSnacks&lt;/a>, a monthly art supplies box. It&amp;rsquo;ll be random (doesn&amp;rsquo;t always come on the same day), it&amp;rsquo;ll be dopamine (SOMETHING NEW!), and it&amp;rsquo;ll be a nice way to explore materials. My first box had some water-based pens which have already upped my game a bit.&lt;/p>
&lt;p>&lt;span class="caption">following Proko&amp;rsquo;s &lt;a href="https://www.youtube.com/watch?v=0660Fuih7qo" target="_blank">The Bean&lt;/a> tutorial&lt;/span>&lt;/p>
&lt;h2 class="relative group">Gamification of inputs
&lt;div id="gamification-of-inputs" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#gamification-of-inputs" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>While my heart/gut still has a &lt;a href="https://www.goodreads.com/review/show/2097599255?book_show_action=false&amp;amp;from_review_page=1" target="_blank">&amp;ldquo;fixed mindset&amp;rdquo;&lt;/a> about art - either you have &amp;ldquo;talent&amp;rdquo; or you don&amp;rsquo;t - my head knows that&amp;rsquo;s baloney and practice will make me better. Which means, as they say, butt-in-chair time. One good gamifier is &lt;a href="https://habitica.com/" target="_blank">Habitica&lt;/a>, which casts your life (and chores) as an RPG. TODO is to write my own art-specific, Python-powered productivity game tool.&lt;/p>
&lt;h2 class="relative group">Progress pics
&lt;div id="progress-pics" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#progress-pics" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Proko says to draw the same thing multiple times. I&amp;rsquo;ll do this, and post monthly/quarterly progress pics. Hopefully I&amp;rsquo;ll improve.&lt;/p>
&lt;p>&lt;span class="caption">shitty perspective, sigh&lt;/span>&lt;/p>
&lt;p>&lt;span class="caption">getting &lt;em>much&lt;/em> better at hands&lt;/span>&lt;/p>
&lt;h2 class="relative group">Social performance
&lt;div id="social-performance" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#social-performance" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Profile pics are great places to share some of my latest art; this blog is also a nice repo. Holiday cards?&lt;/p>
&lt;h2 class="relative group">Automation
&lt;div id="automation" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#automation" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Yeah, I gotta do this part. To the Python!&lt;/p>
&lt;hr>
&lt;p>&lt;span class="caption">image from a to-be-written scifi story&lt;/span>&lt;/p>
&lt;h1 class="relative group">More than mere flesh
&lt;div id="more-than-mere-flesh" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#more-than-mere-flesh" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h1>
&lt;p>Okay, with all that depressing &amp;ldquo;let&amp;rsquo;s hack our reptilian brain&amp;rdquo; stuff out of the way, let&amp;rsquo;s speak of higher matters. ART!&lt;/p>
&lt;p>The thing I&amp;rsquo;ve repeatedly noticed about art - in any medium - is that it can give you new eyes to see the world. I&amp;rsquo;ve always liked that feeling. After getting into photography, I would see &amp;ldquo;beautiful shots&amp;rdquo; everywhere. My early love of drawing made me love the human form - e.g. my brain sees wrists as one of the world&amp;rsquo;s most beautiful, intriguing forms, but I only recently began to realize other people might not think that?! Lately, I&amp;rsquo;ve been marveling at &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/03/jacobian_stuff/" target="_blank">perspective and how it can be mathy&lt;/a>.&lt;/p>
&lt;p>I like very much that the Renaissance masters followed this same line of reasoning, since I consider them my go-to heroes and inspiration. Lately, I&amp;rsquo;ve been thinking that I could probably hack my way to better drawing by studying anatomy and geometry. (Yeah, I know, DUH.) But what a sensible and rational and sure-fire path!&lt;/p>
&lt;h2 class="relative group">Goals &amp;amp; inspiration
&lt;div id="goals--inspiration" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#goals--inspiration" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Another thing I like about art is, of course, its ability to tell stories. I &lt;a href="http://www.angelaambroz.com/scifi.html" target="_blank">like telling stories&lt;/a>! Especially, hopefully, weird and wacky ones. I reeeeally admire the &lt;a href="http://fionastaples.tumblr.com/" target="_blank">Fiona Staples&amp;rsquo;s&lt;/a> complete control of form and movement (mamma mia), and &lt;a href="https://royalboiler.wordpress.com/" target="_blank">Brandon Graham&amp;rsquo;s&lt;/a> fevered visions, and - of course - &lt;a href="https://www.moebius.fr/" target="_blank">Jean Giraud/Moebius&amp;rsquo;s&lt;/a> precise, meticulously imagined worlds. I guess my DREAM (!!) would be to approach any of these three&amp;rsquo;s skill in any way possible. Even an inch! So let&amp;rsquo;s see.&lt;/p>
&lt;p>&lt;span class="caption">Fiona Staples&amp;rsquo;s absolute mastery and control! no hesitation! every line is perfect!&lt;/span>&lt;/p>
&lt;p>&lt;span class="caption">Brandon Graham&amp;rsquo;s intense, feverish, hallucinatory sci-fi style&lt;/span>&lt;/p>
&lt;p>&lt;span class="caption">Moebius&amp;rsquo;s rich, clear, meticulous visions&lt;/span>&lt;/p></description></item><item><title>Starting CS50</title><link>https://www.angelaambroz.com/posts/cs50_lecture_1/</link><pubDate>Fri, 19 Jan 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/cs50_lecture_1/</guid><description>
&lt;h3 class="relative group">Background: What is CS50, and why am I taking it
&lt;div id="background-what-is-cs50-and-why-am-i-taking-it" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#background-what-is-cs50-and-why-am-i-taking-it" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>One big part of my &lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/04/journey_to_the_center_of_data_science/" target="_blank">journey to the center of data science&lt;/a> has been a journey to the center of &lt;em>computer&lt;/em> science. I&amp;rsquo;m a self-taught programmer, and I&amp;rsquo;ve now taken four CS courses in my life: an introductory undergrad CS101 course from looong ago, and three data science-centric CS courses through Harvard&amp;rsquo;s &lt;a href="https://www.extension.harvard.edu/" target="_blank">Extension School&lt;/a>.&lt;/p>
&lt;p>The rest I&amp;rsquo;ve learned on the fly - which has been fun and whirlwindy - but it leaves me with some foundational, I think, gaps. Specifically, I want to focus on:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Data structures and algorithms&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Networking&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>But, before diving into those two, I thought working through Harvard&amp;rsquo;s (crazy popular) &lt;a href="https://cs50.harvard.edu/" target="_blank">CS50&lt;/a> would be a great way to fill in a lot of general fundamentals. Also, it has some problem sets in C! Yay!&lt;/p>
&lt;p>By blogging and &amp;ldquo;learning out loud&amp;rdquo;, I&amp;rsquo;m hoping it&amp;rsquo;ll motivate me to find the time to really crush through this and finish it up. It&amp;rsquo;s 11 weeks of about ~2.5 hours of video and ~4-5 hours of problem sets per week. That&amp;rsquo;s ~75-80 hours. Thanks to &lt;a href="https://courses.edx.org/courses/course-v1:HarvardX&amp;#43;CS50&amp;#43;X/course/" target="_blank">edx.org&amp;rsquo;s instance of CS50X&lt;/a>, everything&amp;rsquo;s released at once, grading (seems to be?) automated, and it&amp;rsquo;s free. I love MOOCs that let you set your own schedule and, if possible, just binge. That&amp;rsquo;s been a lot easier for me to organize around than MOOCs that have enforced week-by-week marches. My schedule is lumpy! Some weeks are free, others are insane.&lt;/p>
&lt;hr>
### Week 0
&lt;h4 class="relative group">Lecture
&lt;div id="lecture" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#lecture" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>The first lecture - or, in compsci nerdery, the 0th lecture - was a fun, edutainment dazzlement of a few core facts: hardware (bits!) and algorithms (ripping up phone books!). What I love about the CS50 behemoth (and it &lt;em>is&lt;/em> a behemoth - with &lt;a href="http://www.thecrimson.com/article/2015/9/9/harvard-curtail-cs50-campaign/" target="_blank">merch&lt;/a>, even) is that its &amp;ldquo;meta&amp;rdquo; - the way it&amp;rsquo;s produced - is clever and fun. I love using their tools. Did they build their own video player?&lt;/p>
&lt;h4 class="relative group">Problem set
&lt;div id="problem-set" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#problem-set" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>I didn&amp;rsquo;t care for PS0. It was meant to be a gentle introduction to programming via MIT&amp;rsquo;s &lt;a href="https://scratch.mit.edu/" target="_blank">Scratch&lt;/a>, a GUI-heavy programming language for kids. I think this &lt;em>could&lt;/em> be useful to demystify programming to someone who&amp;rsquo;s never coded before; I&amp;rsquo;m not sure. It introduces the basic concepts of loops, conditionals, and variables. I found it a chore and rushed through it. Let&amp;rsquo;s get to C!&lt;/p>
&lt;hr>
### Week 1
&lt;h4 class="relative group">Lecture
&lt;div id="lecture-1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#lecture-1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>This explored basic programming ideas with C. If you&amp;rsquo;ve programmed before, the ideas were the basics: loops and conditionals and syntax gotchas, and so on. The main takeaway I had was about compilers (which translate source code, written in C, into assembly language), &lt;code>clang&lt;/code> and its many flags, and &lt;code>make&lt;/code>.&lt;/p>
&lt;p>There was also some fun stuff about floating point imprecision (bane of all my unit tests!) and overflow/underflow. Data types - such as (unsigned) ints, chars, floats, and so on - were introduced.&lt;/p>
&lt;h4 class="relative group">Problem set
&lt;div id="problem-set-1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#problem-set-1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>This PS was our first in C - yay! It covered a couple basic programming tasks: &amp;ldquo;hello, world&amp;rdquo;, drawing some ASCII art inspired by Super Mario, and either implementing a &lt;a href="https://en.wikipedia.org/wiki/Greedy_algorithm" target="_blank">greedy algorithm&lt;/a> for a change-making machine or a credit card &lt;a href="https://en.wikipedia.org/wiki/Cryptographic_hash_function" target="_blank">checksum&lt;/a>, uh, checker. This was all done on CS50&amp;rsquo;s nice, cloud-based (containerized?) IDE. I found it easy (&amp;ldquo;hello, world&amp;rdquo;), medium (Mario), and pretty tricky (greedy algorithm). A good mix!&lt;/p>
&lt;hr>
### Week 1, continued
&lt;h4 class="relative group">Lecture
&lt;div id="lecture-2" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#lecture-2" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>My three main takeaways from this lecture were:&lt;/p>
&lt;ol>
&lt;li>Compiling as a four-step process: preprocessing, compiling, assembling, and linking.&lt;/li>
&lt;li>&lt;code>#include &amp;lt;some_c_library.h&amp;gt;&lt;/code> as the C-equivalent to Python&amp;rsquo;s &lt;code>import&lt;/code> statements.&lt;/li>
&lt;li>Command-line arguments.&lt;/li>
&lt;li>Debuggers.&lt;/li>
&lt;/ol>
&lt;p>Okay, four things. Man, I wish I had known about debuggers back when I first learned to code! Yeesh. I relied (and probably still rely too heavily) on &lt;code>console.log()&lt;/code>/&lt;code>print()&lt;/code> statements, but debuggers offer much richer information about a program&amp;rsquo;s current state, variable values in scope, and all that.&lt;/p>
&lt;h4 class="relative group">Problem set
&lt;div id="problem-set-2" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#problem-set-2" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>Cryptography! So this was basically implementing the Caesar and Vigenere ciphers, something &lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/29/clojure__cryptography__maximum_fun/" target="_blank">I had already done in Clojure&lt;/a>. Still useful, though.&lt;/p>
&lt;hr>
&lt;h3 class="relative group">Impressions so far
&lt;div id="impressions-so-far" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#impressions-so-far" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>The thing about CS50 is that the lectures are super slick but, even better, the problem sets are dense and challenging. I really love the problem sets!&lt;/p>
&lt;p>I remember marveling at the well-designed problem sets of &lt;a href="http://www.cs171.org/2017/index.html" target="_blank">CS171&lt;/a>, &lt;a href="https://canvas.harvard.edu/courses/29726/" target="_blank">CS109A&lt;/a> and &lt;a href="https://canvas.harvard.edu/courses/20101/assignments/syllabus" target="_blank">CS109B&lt;/a>: in all those courses, I had probably learned the most by going through the comprehensive and dense PSs. So I really like that! It takes forever - but, thankfully, CS50 offers &amp;ldquo;less comfortable&amp;rdquo; and &amp;ldquo;more comfortable&amp;rdquo; options. If I have time, I&amp;rsquo;ll work through the &amp;ldquo;hard&amp;rdquo; version (e.g. the Mario ASCII art); if I have less time or feel pooped, I fall back on the &amp;ldquo;easy&amp;rdquo; version (e.g. the greedy algorithm - which was still kinda tricky!). Overall, I&amp;rsquo;m spending ~4 hours on the PSs - which is less than I used to spend on the (not free) Extension School classes (that would be more like 8-10 hours/week, oof).&lt;/p></description></item><item><title>One bash script to blog them all</title><link>https://www.angelaambroz.com/posts/one_bash_script_to_blog_them_all/</link><pubDate>Fri, 12 Jan 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/one_bash_script_to_blog_them_all/</guid><description>&lt;p>One of my &lt;a href="http://angelaambroz.com/blog/posts/2017/Nov/30/hello_pelican/" target="_blank">desired blog specs was automation&lt;/a>. The first automation I made was &lt;code>make_entry.py&lt;/code>, a script modelled on &lt;a href="http://nafiulis.me/making-a-static-blog-with-pelican.html" target="_blank">this blog&amp;rsquo;s example&lt;/a> that would, from the command line, create a fresh new &lt;code>.md&lt;/code> file with my Pelican template stuff filled-in. My latest little automation is a script I named &lt;code>picard.sh&lt;/code> (because &lt;code>makeitso.sh&lt;/code> was too annoying to type).&lt;/p>
&lt;p>&lt;code>picard.sh&lt;/code> automates the process of &lt;code>Pelican making -&amp;gt; publishing to my webhost -&amp;gt; updating Twitter&lt;/code>. It&amp;rsquo;s super simple, and I&amp;rsquo;ll be using this blog entry as the first integration test/guinea pig.&lt;/p>
&lt;h2 class="relative group">Step 1: Pelican-make the blog
&lt;div id="step-1-pelican-make-the-blog" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-1-pelican-make-the-blog" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># picard.sh&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Jan 2018. Automate publishing + tweeting.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;Pouring blog out into local angelaambroz/ dir&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">make html
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After creating this blog post, in Markdown and in my &lt;code>blog/content/&lt;/code> folder, I need to run &lt;code>make html&lt;/code> to pour it into the local directory where the rest of my website is. This comes built-in with Pelican (&lt;a href="http://docs.getpelican.com/en/3.6.3/publish.html#make" target="_blank">docs&lt;/a>).&lt;/p>
&lt;h2 class="relative group">Step 2: Securely copying my local website copy onto my webhost server, using &lt;code>ssh&lt;/code>
&lt;div id="step-2-securely-copying-my-local-website-copy-onto-my-webhost-server-using-ssh" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-2-securely-copying-my-local-website-copy-onto-my-webhost-server-using-ssh" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Oh man, how I love SSH (secure shell)! I could go on and on about it. And I love &lt;code>scp&lt;/code> (secure copy protocol), which lets you copy files and folders to remote servers. It&amp;rsquo;s awesome.&lt;/p>
&lt;p>Before I could get &lt;code>picard.sh&lt;/code> (or any bash scripting into remote servers) to work, then, I needed to get an SSH handshake set up between me and the webhost. I did this:&lt;/p>
&lt;ol>
&lt;li>Create new SSH keys, specific to my webhost&amp;rsquo;s server, with &lt;code>ssh-keygen&lt;/code>.&lt;/li>
&lt;li>Put those keys on the server via the UI. This is similar to how it works on GitHub. Further reading: &lt;a href="https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/" target="_blank">Adding a new SSH key to your GitHub account&lt;/a>&lt;/li>
&lt;li>Set up my &lt;code>.ssh/config&lt;/code> file to use only &lt;em>those&lt;/em> website-specific keys when SSHing or SCPing into that server. Further reading: &lt;a href="https://stuff-things.net/2016/07/06/ssh-too-many-authentication-failures/" target="_blank">SSH - Too Many Authentication Failures&lt;/a>. This was to troubleshoot a &amp;ldquo;too many attempts&amp;rdquo; disconnection I kept getting. It was trying all my other SSH keys.&lt;/li>
&lt;/ol>
&lt;p>Once all that was done, I could now securely connect to my website from the command line. Awesome! I copied a test file over with &lt;code>scp&lt;/code>, and voila! Things were ready. I added the following to &lt;code>picard.sh&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;SCPing over to angelaambroz.com&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">scp -r /path/to/local/website/blog my_username@my_webhost:~/path/to/website/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 class="relative group">Step 3: Let Twitter know
&lt;div id="step-3-let-twitter-know" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-3-let-twitter-know" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Okay, so I&amp;rsquo;m skipping over a Python script that I wrote, &lt;code>update_twitter.py&lt;/code>, that tells the Twitter world about a new blog post when it happens. It&amp;rsquo;s not terribly interesting, or terribly different from my post on &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/02/making_a_twitter_bot/" target="_blank">Making a Twitter bot&lt;/a>. Here&amp;rsquo;s the only different stuff:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">_make_link&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">blog_slug&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">blog_date&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Example link: http://angelaambroz.com/blog/posts/2017/Dec/21/data_is_my_copilot/
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Twitter will handle link shortening via t.co
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> (https://help.twitter.com/en/using-twitter/how-to-tweet-a-link)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base_url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;http://angelaambroz.com/blog/posts&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strptime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">blog_date&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1"> %H:%M&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">year&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">year&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">month&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%b&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">day&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">day&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">base_url&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">year&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">month&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">day&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">blog_slug&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/index.html&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">tweet_about_blog&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">connection&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Tweet about post
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">robot_emoji&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="se">\xf0\x9f\xa4\x96&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_make_link&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;slug&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">post&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tweet&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">bytes&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;blurb&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;utf-8&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">robot_emoji&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">connection&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">update_status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tweet&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_last_n_blog_entries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Grab last n (default=1) blog entries from the content/ folders&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">latest_blog_posts&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">sorted&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">listdir&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;content/&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="s2">&amp;#34;.md&amp;#34;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">])[&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">:]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">title_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">blog_post&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">latest_blog_posts&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;content/&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">blog_post&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">blog_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">readlines&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">title&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">blog_list&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="s1">&amp;#39;Title: &amp;#39;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">slug&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">blog_list&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="s1">&amp;#39;Slug: &amp;#39;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">blog_list&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="s1">&amp;#39;Date: &amp;#39;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">title_list&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;blurb&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">title&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Title: &amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;New blog: &amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;slug&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">slug&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Slug: &amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Date: &amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">title_list&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The most interesting hm!-inducing stuff in this Python script were just:&lt;/p>
&lt;ul>
&lt;li>Finding the the unicode (or is it hex? what is that thing?) for the &lt;code>robot_emoji&lt;/code>.&lt;/li>
&lt;li>List comprehensions are always nice? e.g. &lt;code>latest_blog_post = sorted([x for x in os.listdir('content/') if &amp;quot;.md&amp;quot; in x])[-n:]&lt;/code>&lt;/li>
&lt;li>I&amp;rsquo;m still in love with Python 3.6&amp;rsquo;s fancy print formatting, &lt;code>f&amp;quot;Hello, {variable_for_name}!&amp;quot;&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>All that said, it just pops into &lt;code>picard.sh&lt;/code> like so:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;Updating Twitter...&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">python update_twitter.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;Done!&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And that&amp;rsquo;s it!&lt;/p>
&lt;p>And, okay, I just realized I could have used &lt;code>publishconf.py&lt;/code> or &lt;code>fabfile.py&lt;/code> (both built-in Pelican publishing tools) for this&amp;hellip; Oop!&lt;/p></description></item><item><title>How to understand the big, wide codebase, and your place in it</title><link>https://www.angelaambroz.com/posts/understanding_a_big_wide_codebase/</link><pubDate>Wed, 10 Jan 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/understanding_a_big_wide_codebase/</guid><description>&lt;p>Learning how to dive into a big, wide codebase is - I&amp;rsquo;m realizing - an important meta-skill. Kinda like &lt;a href="https://violentmetaphors.com/2013/08/25/how-to-read-and-understand-a-scientific-paper-2/" target="_blank">learning how to read an academic article&lt;/a>.&lt;/p>
&lt;p>I&amp;rsquo;ve struggled with it, though, since I didn&amp;rsquo;t realize it &lt;em>was&lt;/em> a meta-skill and something to improve. I guess I thought other people just magically absorbed big codebases?! That, coupled with the shrieking sirens of &lt;a href="https://en.wikipedia.org/wiki/Impostor_syndrome" target="_blank">impostor syndrome&lt;/a>, made me freeze up whenever someone asked me, &amp;ldquo;Hey, could you make [X small change] to [Y giant new codebase]?&amp;rdquo;&lt;/p>
&lt;p>So I wanted to note down what I do and what&amp;rsquo;s been helpful.&lt;/p>
&lt;h2 class="relative group">Objective
&lt;div id="objective" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#objective" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Imagine, if you will, this scenario:&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>SCENE 1. A bustling 15th century RENAISSANCE BOTTEGA. Large lavendar plants spill from big ceramic jars. The work of the great Renaissance masters - Da Vinci, Brunelleschi, Michelangelo - adorn the walls, along with a cyberpunk poster or two. The smell of paper-thin pizza is in the air. Your COLLEAGUE is laboring over some giant convolutional neural net. YOU arrive, stage left, &lt;a href="http://www.shakespeare-online.com/plays/winter_3_3.html" target="_blank">pursued by a bear&lt;/a>.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>COLLEAGUE: Oh! Angela! Welcome to the team. Glad you could join us.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOU: (nervously) Glad to be here!&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>COLLEAGUE: We thought a nice first project for you would be extending some of the features for our service&amp;rsquo;s chatbot.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOU: &amp;hellip;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>COLLEAGUE: Are your familiar with chatbots?&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOU: Um, well, I guess I did &lt;a href="https://github.com/hks-epod/odo-bot/" target="_blank">build one&lt;/a> in my old job, but that was just &amp;ndash;&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>COLLEAGUE: &lt;em>GREAT!&lt;/em> Ours is powered by some natural language processing, regular expressions, and a few APIs. Pretty straightforward, really, no big deal. We&amp;rsquo;d love it if it could start responding to user questions about our DATA SCIENCE SERVICE, so you&amp;rsquo;ll need to plug it into that as well. We&amp;rsquo;re just trying to give a window into that infamous black box, eh?&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>The DATA SCIENCE SERVICE is wheeled out. It is a large black box, thrumming softly and crackling with occasional bursts of electric sparks. There is a small post-it attached that reads: &lt;code>README.md&lt;/code>. YOU peer at the post-it, peer at the box, and the blood drains from your face. It reminds me you of &lt;a href="https://www.youtube.com/watch?v=AGqdE1NdMTg" target="_blank">that one freaky Dune scene&lt;/a>. You think you hear the hiss of snakes inside.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOU: (to self) Oh God.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>COLLEAGUE: Sorry?&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOU: I said, sounds great!&lt;/p>
&lt;/blockquote>
&lt;p>So. What to do?&lt;/p>
&lt;p>This has happened a few times, where I&amp;rsquo;ll be introduced to a codebase that has thousands of lines of code spread out over several modules. It can be really intimidating! So this is how I break it down.&lt;/p>
&lt;h2 class="relative group">Step 1: Get the general context
&lt;div id="step-1-get-the-general-context" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-1-get-the-general-context" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The biggest mistake I make - and I make it again and again - is that I get into the weeds too fast. Whenever I&amp;rsquo;m introduced to a black box, I find the first weed and start studying it very, very closely. This is no good. This is not just putting the cart before the horse, this is putting the screws before the wheels before the cart before the horse.&lt;/p>
&lt;p>So, one thing I&amp;rsquo;ve been training myself to do is a &lt;strong>top down approach&lt;/strong>. Mainly, this means asking myself, before anything: &lt;em>What is the point of this codebase?&lt;/em> If I can describe it in one line (e.g. &amp;ldquo;It&amp;rsquo;s a micro-service that provides a probable classification in response to an HTTP request&amp;rdquo;), that&amp;rsquo;s a start.&lt;/p>
&lt;p>Beyond getting the one-line tldr of the overall, I then try to build out the context more. Why does this codebase exist? What happened before it existed? Who uses it? If there&amp;rsquo;s documentation, I try to read it - even if it&amp;rsquo;s outdated. I try to ask stupid questions, and keep asking them. I try to draw out a diagram of its place in the world (e.g. connected to databases or a website or what).&lt;/p>
&lt;p>&lt;span class="caption">I love my LCD writer - perfect extension for your brain!&lt;/span>&lt;/p>
&lt;h2 class="relative group">Step 2: Get the software context
&lt;div id="step-2-get-the-software-context" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-2-get-the-software-context" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>If you don&amp;rsquo;t have lots of software development experience, directory structures look pretty arbitrary. When I realized that there were norms around how code projects were organized, this sped things up &lt;em>a lot&lt;/em>. Suddenly, I knew where to look; I knew which folders to focus on. The &lt;a href="http://docs.python-guide.org/en/latest/writing/structure/" target="_blank">&lt;em>Hitchhiker&amp;rsquo;s Guide to Python&lt;/em> has a good overview of a Python project template&lt;/a>, and I&amp;rsquo;ve also seen and used &lt;a href="https://drivendata.github.io/cookiecutter-data-science/" target="_blank">DrivenData&amp;rsquo;s cookiecutter data science template&lt;/a>.&lt;/p>
&lt;h2 class="relative group">Step 3: The project outline (drawn)
&lt;div id="step-3-the-project-outline-drawn" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-3-the-project-outline-drawn" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I find it really helpful to draw a diagram linking all the modules together. Sometimes this includes drilling down into each module, mapping the functions too and whether they&amp;rsquo;re calling external stuff (like a database) or calling other pieces. The main thing I want to do is get a sense of &lt;em>what&amp;rsquo;s in there&lt;/em>.&lt;/p>
&lt;p>I also am a big fan of color-coded everything, since - thanks to &lt;a href="http://www.cs171.org/2016/index.html" target="_blank">CS171&lt;/a> - I now know that COLOR REIGNS SUPREME, and the human brain processes color blaaazingly fast (yeah, &lt;a href="https://en.wikipedia.org/wiki/Visual_cortex" target="_blank">V1 neurons!&lt;/a>).&lt;/p>
&lt;p>&lt;span class="caption">Blue classes hold red functions&lt;/span>&lt;/p>
&lt;h2 class="relative group">Step 4: Reading and writing docstrings
&lt;div id="step-4-reading-and-writing-docstrings" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-4-reading-and-writing-docstrings" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Once the above steps are done, I feel like I am NOW ALLOWED INTO THE WEEDS. At this point, I&amp;rsquo;ll start digging into specific functions by order of subjective &amp;ldquo;importance&amp;rdquo;. I really like &lt;a href="https://www.jetbrains.com/help/pycharm/viewing-definition.html" target="_blank">PyCharm&amp;rsquo;s goto definition&lt;/a> thing - where I can &lt;code>cmd+some_function_name()&lt;/code> and it&amp;rsquo;ll jump me to the source. I&amp;rsquo;ll try to follow this goto-stream up and down the layers of abstraction, reading through docstrings.&lt;/p>
&lt;p>Unless there aren&amp;rsquo;t any docstrings! Which sometimes happen! In this case, I might start drafting some docstrings for the functions - just (1) what I think the func does, (2) arguments and their data types, (3) returned values and their types. I&amp;rsquo;ll try to understand the funcs well enough to write docstrings that could be merged into the &lt;code>develop&lt;/code> branch.&lt;/p>
&lt;h2 class="relative group">Also step 4: Running and writing tests
&lt;div id="also-step-4-running-and-writing-tests" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#also-step-4-running-and-writing-tests" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I recently learned about the wonders of testing, and now I use tests as my sanity check for everything. When I&amp;rsquo;m getting to know a new codebase, I might run tests as the first thing I do - this often pops out whether my installation or virtual environment is missing something. And that helps understanding too! I also try to read through the tests and see what&amp;rsquo;s being tested; this can be the best place to see the overarching behavior of all the code.&lt;/p>
&lt;p>I&amp;rsquo;ve lately also found that writing tests - especially super small unit tests - and checking out test coverage, are reeeeally helpful ways to get to know things better. Robin Andeer&amp;rsquo;s three part series &amp;ndash;&lt;/p>
&lt;ol>
&lt;li>&lt;a href="http://www.robinandeer.com/blog/2016/06/18/how-i-test-my-code-part-1/" target="_blank">How I test my code: motivation and strategy (part 1)&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.robinandeer.com/blog/2016/06/21/how-i-test-my-code-part-2/" target="_blank">How I test my code: pytest and fixtures (part 2)&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://www.robinandeer.com/blog/2016/06/22/how-i-test-my-code-part-3/" target="_blank">How I test my code: coverage and automation (part 3)&lt;/a>&lt;/li>
&lt;/ol>
&lt;p>&amp;ndash; was really eye-opening.&lt;/p>
&lt;h2 class="relative group">The last step 4: Jupyter notebooks
&lt;div id="the-last-step-4-jupyter-notebooks" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#the-last-step-4-jupyter-notebooks" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>And finally, Jupyter notebooks! This has also been a helpful way to get to know code. By this point, I should have an overall sense of what the codebase is supposed to be doing. I might want to dig into an important or main function. A good way to do that is, after creating a virtual environment and &lt;code>pip&lt;/code> installing the project&amp;rsquo;s dependencies, creating a (&lt;code>.gitignore&lt;/code>d!) folder called &lt;code>notebooks/&lt;/code> and starting to explore the tests, the code, everything. One thing I might do is pull in a function and break it down into each of its parts - that way, I can see what goes where, and what needs what.&lt;/p>
&lt;p>A slightly more onerous way, and something I sometimes do with testing as well, is just splattering &lt;code>print()&lt;/code> statements everywhere, especially of parameters and returned values. This helps me understand the state of things at each point in the code.&lt;/p>
&lt;h2 class="relative group">I&amp;rsquo;m still not great at this
&lt;div id="im-still-not-great-at-this" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#im-still-not-great-at-this" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>That&amp;rsquo;s been the journey so far. And that&amp;rsquo;s my current best method. If I were to boil it down, it would be: (1) top-down first, (2) draw, (3) test (safely).&lt;/p></description></item><item><title>Git history is written by the victors</title><link>https://www.angelaambroz.com/posts/git_history_is_written_by_the_victors/</link><pubDate>Tue, 09 Jan 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/git_history_is_written_by_the_victors/</guid><description>&lt;p>When I career switched into tech, the two big management shocks were daily standup and &lt;code>git&lt;/code>. And I mean that in a good way, a very good way. I love &lt;code>git&lt;/code> very much, and am starting to get opinionated about it. It&amp;rsquo;s not just version control! It&amp;rsquo;s history, and narrative, and structure. It&amp;rsquo;s collaboration! It&amp;rsquo;s TEAM. It&amp;rsquo;s a beautiful tree spawning many branches. Or a lot of hair with a lot of braids that need to get re-braided. I like to keep my repos like little bonsais or Princess Leia buns of good practice. &lt;code>git&lt;/code> is not to be neglected! And often is!&lt;/p>
&lt;p>&lt;span class="caption">&lt;a href="https://xkcd.com/1296/" target="_blank">xkcd/1296&lt;/a>&lt;/span>&lt;/p>
&lt;h2 class="relative group">Tutorial assumptions
&lt;div id="tutorial-assumptions" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#tutorial-assumptions" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This tutorial assumes that you have used &lt;code>git&lt;/code>, at least a little bit. That is, you know that it&amp;rsquo;s a version control system, you&amp;rsquo;ve made some commits, pushed and pulled, and have an account on GitHub. If you&amp;rsquo;re very new to &lt;code>git&lt;/code>, then I highly recommend Udacity&amp;rsquo;s &lt;a href="https://www.udacity.com/course/how-to-use-git-and-github--ud775" target="_blank">How to Use Git and GitHub&lt;/a>.&lt;/p>
&lt;h2 class="relative group">Some philosophy: Git as history (AKA the power of &lt;code>squash&lt;/code> and &lt;code>rebase&lt;/code>)
&lt;div id="some-philosophy-git-as-history-aka-the-power-of-squash-and-rebase" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#some-philosophy-git-as-history-aka-the-power-of-squash-and-rebase" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I think the main power of &lt;code>git&lt;/code> is that it tells a story of your project. Sometimes I get lazy and just rely on &lt;code>git&lt;/code> to, well, not lose all my stuff. And this is, yeah, its big sell. But, if you write good (long!) commit messages and commit at the Right Time, and if you wield the majestic power of &lt;code>git squash&lt;/code> and &lt;code>git rebase&lt;/code> with aplomb, I think you can create quite a beautiful, readable little story, something to be passed down from collaborator to collaborator. This is useful for welcoming new team members, or for dealing with the passage of time (why did you write it that way, all those months ago?).&lt;/p>
&lt;p>Here are some stuff I find helpful in &lt;code>git&lt;/code>:&lt;/p>
&lt;h3 class="relative group">1. Visualize your history
&lt;div id="1-visualize-your-history" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#1-visualize-your-history" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>There are several ways to visualize git histories:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.git-tower.com/" target="_blank">Tower&lt;/a> ($80/license) - A very pretty GUI, integrates nicely with GitHub.&lt;/li>
&lt;li>&lt;code>gitk&lt;/code> - A built-in command-line &amp;ldquo;graphical repository browser&amp;rdquo; that ships with git. Uglier GUI than Tower.&lt;/li>
&lt;li>A bash alias:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">alias&lt;/span> &lt;span class="nv">glg&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;git log --graph --full-history --all --color --pretty=format:&amp;#34;%x1b[31m%h%x09%x1b[32m%d%x1b[0m%x20%s&amp;#34;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I don&amp;rsquo;t know who wrote the above. Someone at my &lt;a href="https://www.pixability.com/" target="_blank">old gig&lt;/a>? It was passed down to me from the ancients. If this was you, &lt;strong>please let me know&lt;/strong>. I feel super guilty sharing some mystery code like this. &lt;strong>Please let me assuage my guilt and just say you wrote this.&lt;/strong>&lt;/p>
&lt;p>Anyway, the point is: find some way to visually navigate through the commit history and the various branches. Git is surprisingly/eerily smart about tracking when things are happening in relation to each other. &lt;em>Seeing&lt;/em> all that is powerful and informative. I &lt;code>glg&lt;/code> repeatedly throughout the day. I just checked now &amp;ndash;&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">history&lt;/span> &lt;span class="p">|&lt;/span> grep glg &lt;span class="p">|&lt;/span> wc -l
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt; &lt;span class="m">34&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&amp;ndash; 34 times! That&amp;rsquo;s 13 times an hour, or once every 4.6 minutes.&lt;/p>
&lt;p>Okay, maybe I check it too much.&lt;/p>
&lt;h3 class="relative group">2. Pick a comfy editor
&lt;div id="2-pick-a-comfy-editor" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#2-pick-a-comfy-editor" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Git uses your global default &lt;code>$EDITOR&lt;/code> as its own. I think that&amp;rsquo;s Vim on OSX? Or is it &lt;code>nano&lt;/code>? Anyway, I like &lt;a href="https://www.sublimetext.com/3" target="_blank">Sublime&lt;/a> as my lightweight &amp;ldquo;small jobs&amp;rdquo; editor. If you want to change your default text editor for &lt;code>git&lt;/code> to Sublime (but keep whatever &lt;code>$EDITOR&lt;/code> for other stuff), then:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git config --global core.editor &lt;span class="s2">&amp;#34;subl -n -w&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You can also do &lt;a href="https://help.github.com/articles/associating-text-editors-with-git/" target="_blank">Atom or TextMate&lt;/a>, or anything that launches from the command line.&lt;/p>
&lt;p>Having a comfy/friendly text editor is important so I can write long, involved commit messages (further reading: &lt;a href="https://chris.beams.io/posts/git-commit/" target="_blank">How to Write a Git Commit Message&lt;/a>).&lt;/p>
&lt;h3 class="relative group">3. Rewrite history (responsibly): &lt;code>git squash&lt;/code>, &lt;code>git rebase&lt;/code>
&lt;div id="3-rewrite-history-responsibly-git-squash-git-rebase" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#3-rewrite-history-responsibly-git-squash-git-rebase" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>When we&amp;rsquo;re working on our local machines, we can create as many branches as we like, however we like. We can commit whenever and whatever. But this can get messy when we start sharing that history around.&lt;/p>
&lt;blockquote>
&lt;p>I fucked up Git so bad it turned into Guitar Hero &lt;a href="https://pic.twitter.com/vUKZJAQKWg" target="_blank">pic.twitter.com/vUKZJAQKWg&lt;/a>
&amp;ndash; Huenry Hueffman (@HenryHoffman) &lt;a href="https://twitter.com/HenryHoffman/status/694184106440200192?ref_src=twsrc%5Etfw" target="_blank">February 1, 2016&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;p>One way to keep things clean is to combine many commits into one big commit (&lt;code>git squash&lt;/code>) and to rewrite our git history such that our suggested changes are always on top of the newest version of code (&lt;code>git rebase&lt;/code>).&lt;/p>
&lt;p>Git squashing and rebasing is useful but potentially destructive. It rewrites git history. I think a good general rule of thumb is: &lt;strong>rewrite your own history, not other people&amp;rsquo;s&lt;/strong>. In other words, right before submitting a pull request, you can combine all your branch commits into one - &amp;ldquo;This is my final version!&amp;rdquo; - and you rebase that one commit on top of the latest &lt;code>develop&lt;/code> branch such that it looks like you used the freshest codebase to start your branch from.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>But you never want to squash or rebase &lt;code>master&lt;/code> or &lt;code>develop&lt;/code> themselves.&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>&lt;code>git rebase&lt;/code> is distinct from &lt;code>git merge&lt;/code> since it doesn&amp;rsquo;t &lt;em>merge&lt;/em> in other people&amp;rsquo;s commits (thus sullying your story), but rather just pretends you started work on whatever the latest code is.&lt;/p>
&lt;p>The end goal is this:
&lt;span class="caption">&amp;ldquo;beautifull&amp;rdquo;&lt;/span>&lt;/p>
&lt;h4 class="relative group">Walkthrough
&lt;div id="walkthrough" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#walkthrough" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h4>
&lt;p>Let&amp;rsquo;s assume you&amp;rsquo;ve been working on a branch for a few days. You have some code you want to PR into &lt;code>blog/master&lt;/code>.&lt;/p>
&lt;ol>
&lt;li>Update your local copy of the master branch with any remote commits.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git fetch
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>If there are any updates, rebase your work on top of those changes in master.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout &lt;span class="o">[&lt;/span>my branch&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase master
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This might be a pain point: merge conflicts. Untangle each of them in turn (I like grepping for &lt;code>&amp;lt;&amp;lt;&amp;lt;&lt;/code> in the conflict files), &lt;code>git add .&lt;/code> them and then &lt;code>git rebase --continue&lt;/code>.&lt;/p>
&lt;p>Now it should look like this:
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="http://blogs.atlassian.com/wp-content/uploads/rebase-diagram-adg3.png" alt="git history" />
&lt;/figure>
&lt;span class="caption">Source: &lt;a href="https://www.atlassian.com/blog/sourcetree/interactive-rebase-sourcetree" target="_blank">https://www.atlassian.com/blog/sourcetree/interactive-rebase-sourcetree&lt;/a>&lt;/span>&lt;/p>
&lt;ol start="3">
&lt;li>Squash your commits (which you can count down from &lt;code>HEAD&lt;/code> to where your work begins, or use a specific commit&amp;rsquo;s SHA) into one final commit. For example, say you wanted to squash the last five commits:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Rebase by counting down from the HEAD...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase -i HEAD~5
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ...or by selecting a specific, older commit&amp;#39;s SHA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase -i 9b20280
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The interactive &lt;code>-i&lt;/code> flag will launch &lt;code>git&lt;/code>&amp;rsquo;s default editor. There, you select which commits to keep as separate commits (&lt;code>pick&lt;/code>, or &lt;code>p&lt;/code>) and which to combine (&lt;code>squash&lt;/code>, &lt;code>s&lt;/code>).&lt;/p>
&lt;blockquote>
&lt;p>Pro tip: If you forget the &lt;code>-i&lt;/code> flag, &lt;code>git&lt;/code> will not squash anything, and will just exit out back to your shell.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;code>pick&lt;/code> your branch&amp;rsquo;s first commit, and &lt;code>s&lt;/code> (squash) all the others.&lt;/p>
&lt;p>Next, git will prompt you to adjust the squashed commit message.&lt;/p>
&lt;p>Check your git history, and voila! You should see that all those commits collapsed into one!&lt;/p>
&lt;h3 class="relative group">4. Keep polishing your git skills
&lt;div id="4-keep-polishing-your-git-skills" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#4-keep-polishing-your-git-skills" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>In my day to day &lt;code>git&lt;/code>, I&amp;rsquo;ve always tried to note down the random stuff I&amp;rsquo;ve learned about how to use it. &lt;em>Can I search for a specific piece of code? Even if it&amp;rsquo;s been deleted? Can I search for a deleted file?&lt;/em> Stuff like that. The mystical &lt;code>.git&lt;/code> file keeps track of so much, and it&amp;rsquo;s great to be able to essentially trawl back through all these different versions of the past.&lt;/p>
&lt;p>Here are some useful recent TILs:&lt;/p>
&lt;ul>
&lt;li>To search all commit history for when a &lt;code>string&lt;/code> changed:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git log -Sstring
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>To compare the differences between specific commits:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git diff COMMIT_SHA^ COMMIT_SHA
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>To remove stuff from the staging area:&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git reset
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(I know, I know. That one should be basic, but I almost never used it, yolooooo.)&lt;/p></description></item><item><title>Jacobi(a)n stuff</title><link>https://www.angelaambroz.com/posts/jacobian_stuff/</link><pubDate>Wed, 03 Jan 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/jacobian_stuff/</guid><description>&lt;p>Somebody mentioned a &amp;ldquo;Jacobian&amp;rdquo; at work - which sounded exotic and mathy and attractive. I resolved to watch the &lt;a href="https://www.khanacademy.org/math/multivariable-calculus/multivariable-derivatives/jacobian/v/jacobian-prerequisite-knowledge" target="_blank">Khan Academy videos on the Jacobian&lt;/a> and learn, dammit, LEARNNNN!&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>til tldr&lt;/strong>: You can use the &lt;a href="https://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant" target="_blank">Jacobian matrix, and its determinant&lt;/a>, to figure out locally linear transformations to small ranges around points, when they&amp;rsquo;ve been all warped up by a non-linear transformation. Apparently this is useful for &lt;a href="https://en.wikipedia.org/wiki/Non-linear_least_squares" target="_blank">non-linear least squares regression&lt;/a>. I&amp;rsquo;m passively looking for more real world examples.&lt;/p>
&lt;/blockquote>
&lt;br>
&lt;h2 class="relative group">Linear algebra is linear
&lt;div id="linear-algebra-is-linear" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#linear-algebra-is-linear" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;ve been working my way through &lt;a href="https://www.khanacademy.org/math/linear-algebra" target="_blank">Khan Academy&amp;rsquo;s linear algebra series&lt;/a> which is (a) very good and (b) very long (it&amp;rsquo;s been months!). I took linear algebra long ago as an undergrad of yore, and had fuzzy memories of (a) how matrices can be multiplied a bunch of different ways (dot? inner? cross?), (b) eigenvalues are important, and (c) ORTHOGONAL. I remember enjoying it, but I was and am very rusty.&lt;/p>
&lt;p>When I got into data science, I loved learning about &lt;a href="https://en.wikipedia.org/wiki/Principal_component_analysis" target="_blank">principal component analysis&lt;/a> and, of course, deep learning, but I also realized, the time for a linear algebra refresher was nigh upon me. I highly recommend Khan for these things.&lt;/p>
&lt;p>I&amp;rsquo;m about halfway through, and the biggest takeaway is the elegance and omnipresence and convenience of linear transformation matrices. And what you can do with them! And how they can encode so much information! Also, the frisson of &lt;a href="https://en.wikipedia.org/wiki/Linear_independence" target="_blank">linear independence&lt;/a> - i.e. &lt;em>more information&lt;/em>.&lt;/p>
&lt;p>I think it&amp;rsquo;s valuable/helpful to visualize the geometry of this stuff, so &lt;a href="https://www.khanacademy.org/math/linear-algebra/matrix-transformations/linear-transformations/a/visualizing-linear-transformations" target="_blank">here&amp;rsquo;s some great visualizations (Khan again)&lt;/a>:&lt;/p>
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/XUw95PFP1RE?rel=0" frameborder="0" gesture="media" allow="encrypted-media" allowfullscreen>&lt;/iframe>
&lt;p>&amp;ndash; &lt;a href="https://www.khanacademy.org/math/linear-algebra/matrix-transformations/linear-transformations/a/visualizing-linear-transformations" target="_blank">an example of a linear transformation&lt;/a>&lt;/p>
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/x1dGfxBdDlM?rel=0" frameborder="0" gesture="media" allow="encrypted-media" allowfullscreen>&lt;/iframe>
&lt;p>&amp;ndash; &lt;a href="https://www.khanacademy.org/math/linear-algebra/matrix-transformations/linear-transformations/a/visualizing-linear-transformations" target="_blank">an example of a non-linear transformation, a SQUIGGLE FEST, a science fiction opus waiting to be written&lt;/a>&lt;/p>
&lt;h2 class="relative group">A case of the squiggles: What to do with non-linear transformations
&lt;div id="a-case-of-the-squiggles-what-to-do-with-non-linear-transformations" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#a-case-of-the-squiggles-what-to-do-with-non-linear-transformations" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>So most of the Khan linear algebra I&amp;rsquo;ve been doing has been watching Sal Khan work through proofs of all the conveniences and glories of having everything linear. And just generally demonstrating how these two simple rules:&lt;/p>
&lt;p>$$T(\bar{v} + \bar{w}) = T(\bar{v}) + T(\bar{w})$$
$$T(\alpha \bar{v}) = \alpha T(\bar{v})$$&lt;/p>
&lt;p>for any vectors, $\bar{v}$ and $\bar{w}$, any scalar $\alpha$ and any matrix transformation $T$, can lead to a lot of helpful results.&lt;/p>
&lt;p>But what about &lt;em>non-linear&lt;/em> transformations? Those would fail the two rules above, and a lot of linear algebra&amp;rsquo;s stuff would break down. It&amp;rsquo;s been likewise YEARS since I did any calculus, so it was fun and interesting to learn - in the &lt;a href="https://www.khanacademy.org/math/multivariable-calculus/multivariable-derivatives/jacobian/v/jacobian-prerequisite-knowledge" target="_blank">Jacobian videos&lt;/a> - about how multivariable calculus tries to port the insights of linear algebra onto non-linear problems.&lt;/p>
&lt;p>Specifically, the Jacobian matrix is based on the premise that, for local ranges around a point, things stay pretty linear even in the most abominable of squiggle-fests. Or, as &lt;a href="https://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant" target="_blank">Wiki&lt;/a> explains,&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;The Jacobian matrix is important because if the function $f$ is differentiable at a point $x$ (this is a slightly stronger condition than merely requiring that all partial derivatives exist there), then the Jacobian matrix defines a linear map $\mathbb{R}^{n} \rightarrow \mathbb{R}^{m}$, which is the best (pointwise) linear approximation of the function $f$ near the point $x$. This linear map is thus the generalization of the usual notion of derivative, and is called the derivative or the differential of $f$ at $x$.&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>Visually:&lt;/p>
&lt;p>&amp;ndash; screenshot from &lt;a href="https://www.khanacademy.org/math/multivariable-calculus/multivariable-derivatives/jacobian/v/local-linearity-for-a-multivariable-function" target="_blank">Khan Academy: Local linearity for a multivariable function&lt;/a>&lt;/p>
&lt;p>And in plainer English (explaining it to myself): the insight of local linearity lets us do a nice trick: by taking the partial derivatives of the original (non-linear) transformation for the $x$ and $y$ directions (in the 2D example), we can get a sense of how points would be transformed by a non-linear transformation, $f$, in a local space.&lt;/p>
&lt;p>Even &lt;em>more&lt;/em> cool was that, in a 2D space, the determinant of that transformation (when written as the transformed basis vector) was the &lt;em>scaled change in that area!&lt;/em> WOW! See &lt;a href="https://www.math.ucdavis.edu/~daddel/linear_algebra_appl/Applications/Determinant/Determinant/node4.html" target="_blank">here&lt;/a> and &lt;a href="http://mathinsight.org/relationship_determinants_area_volume" target="_blank">here&lt;/a>. So, when you take the determinant of the Jacobian, you get a sense of how that non-linear transformation changed the area of stuff around that local space. If something was of size 1 before, and you calculate the Jacobian determinant after a non-linear transformation, you can say, &amp;ldquo;Ah ha, now it&amp;rsquo;s size 0.5!&amp;rdquo; Or whatever. And this determinant is different, of course, depending on which point in the space you choose to transform! Because it&amp;rsquo;s &lt;em>non-linear!&lt;/em>&lt;/p>
&lt;h2 class="relative group">Perspective in art
&lt;div id="perspective-in-art" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#perspective-in-art" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>So yesterday I doodled Oxford&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/Radcliffe_Camera" target="_blank">Radcliffe Camera&lt;/a> &amp;ndash;&lt;/p>
&lt;p>&amp;ndash; and was VERY irritated with my total perspective fail.&lt;/p>
&lt;p>And, as I was watching the linear algebra videos, and Sal Khan was mentioning the application to 3D game development, I realized: &lt;a href="https://en.wikipedia.org/wiki/Perspective_%28graphical%29" target="_blank">VANISHING POINTS!&lt;/a>&lt;/p>
&lt;p>This led me, so happily, to the power and glory of Italian Renaissance genius - that most inspiring of geniusnesses. It was the Italian Renaissance masters - Brunelleschi, specifically, who built Florence&amp;rsquo;s magnificent cathedral - that realized how &lt;a href="https://en.wikipedia.org/wiki/Perspective_%28graphical%29#Renaissance:_mathematical_basis" target="_blank">perspective was a mathematical and geometric property&lt;/a>. So glorious! So reliable! I got really pumped about this, and about how linear transformations could be applied to art.&lt;/p>
&lt;h2 class="relative group">Jacobian, not Jacobin
&lt;div id="jacobian-not-jacobin" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#jacobian-not-jacobin" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Har har, well, I found it funny. No, it&amp;rsquo;s not &lt;em>that&lt;/em> &lt;a href="https://www.jacobinmag.com/" target="_blank">Jacobin&lt;/a>. But oooh - an &lt;a href="https://www.jacobinmag.com/2018/01/italian-election-berlusconi-five-star-movement" target="_blank">article about Italy&lt;/a>!&lt;/p>
&lt;h2 class="relative group">TODO
&lt;div id="todo" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#todo" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Write a script to calculate the per-video and total duration of various Khan Academy courses. (Honestly, this should just be on the website!)&lt;/li>
&lt;li>Apply math to art!?&lt;/li>
&lt;/ul></description></item><item><title>Making a Twitter bot</title><link>https://www.angelaambroz.com/posts/making_a_twitter_bot/</link><pubDate>Tue, 02 Jan 2018 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/making_a_twitter_bot/</guid><description>&lt;p>I made my first Twitter bot today. It was surprisingly easy! I was worried I&amp;rsquo;d have to get all up in Oauth&amp;rsquo;s business (please God no), but I didn&amp;rsquo;t. Instead, I managed to go from zero to bot in the length of Philip Glass&amp;rsquo;s &lt;a href="https://open.spotify.com/album/14cjrsQzwbtPAT4eMGZZQu" target="_blank">Koyaanisqatsi&lt;/a>. Aw yiss.&lt;/p>
&lt;p>&amp;ndash; &lt;a href="https://xkcd.com/1646/" target="_blank">xkcd/1646&lt;/a>&lt;/p>
&lt;h2 class="relative group">Specs
&lt;div id="specs" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#specs" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ol>
&lt;li>Auto-delete my old tweets from Twitter.&lt;/li>
&lt;li>Save them somewhere else.&lt;/li>
&lt;/ol>
&lt;br>
## Walkthrough
&lt;p>Let&amp;rsquo;s get started!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">tweepy&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">argparse&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pandas&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">pd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timedelta&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So, I grabbed &lt;code>os&lt;/code> for file management, &lt;code>tweepy&lt;/code> as my Twitter API Python wrapper of choice (&lt;a href="http://www.tweepy.org/" target="_blank">docs&lt;/a>), &lt;code>argparse&lt;/code> for command line arguments, &lt;code>pandas&lt;/code> for lazy data munging, and &lt;code>datetime&lt;/code> stuff for filename management and defining what an &amp;ldquo;old&amp;rdquo; tweet is.&lt;/p>
&lt;p>First, let&amp;rsquo;s connect! After registering my app on &lt;a href="https://apps.twitter.com/" target="_blank">apps.twitter.com&lt;/a>, I granted it &lt;code>Read-Write&lt;/code> access and generated some user tokens. I put these in a local &lt;a href="https://en.wikipedia.org/wiki/Dot-file" target="_blank">dotfile&lt;/a>, because SECURITY. (Incidentally, whoa, check out this cool &lt;a href="https://dotfiles.github.io/" target="_blank">dotfile zoo&lt;/a>&amp;hellip;) I made a &amp;ldquo;hidden&amp;rdquo; function, &lt;code>_connect()&lt;/code>, that&amp;rsquo;ll grab the permissions from my dotfile, do the whole Oauth thing, and return a Tweepy Twitter API object. &amp;ldquo;Hidden&amp;rdquo; because it won&amp;rsquo;t be accessible from the command-line, but rather called from the other main functions (below).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">_connect&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Connecting to Twitter...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumer_secret&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;TWITTER_CSECRET&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumer_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;TWITTER_CKEY&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">access_token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;ACC_TOKEN&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">access_token_secret&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;ACC_SECRET&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tweepy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">OAuthHandler&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">consumer_key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">consumer_secret&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">auth&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">set_access_token&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">access_token&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">access_token_secret&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">tweepy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">API&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">auth&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>At this point, I should really test stuff out&amp;hellip; but&amp;hellip; I was lazy and continued.&lt;/p>
&lt;p>Next, I wanted a function to archive all my tweets. I called this &lt;code>backfill()&lt;/code>. No arguments, because - meh - I can&amp;rsquo;t think of any. It just reads through my entire timeline and archives what&amp;rsquo;s there into a csv, filenamed to the date.&lt;/p>
&lt;blockquote>
&lt;p>Word on the street is Twitter is limiting the tweets it shows you on the website. Via the API, you can grab a default of 20 (or a maximum of 200) tweets from the &lt;code>api.user_timeline()&lt;/code> method. &lt;a href="https://stackoverflow.com/questions/42225364/getting-whole-user-timeline-of-a-twitter-user" target="_blank">This StackOverflow post&lt;/a> includes the &lt;code>for&lt;/code> loop to paginate through and grab up to 3,200 tweets.&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">backfill&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_connect&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_my_tweets&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Downloading all tweets...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">status&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">tweepy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Cursor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">user_timeline&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">all_my_tweets&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">status&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">status&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">created_at&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;text&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">status&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;retweets&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">status&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">retweet_count&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;favorites&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">status&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">favorite_count&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">all_my_tweets&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_csv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">_backfill_twitter.csv&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>After the backfill was done, and my precious old tweets were safe, I wrote the deleter function, &lt;code>delete_old_tweets()&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">delete_old_tweets&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">date&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">_connect&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Ugh filename&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">filename&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">listdir&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="s1">&amp;#39;_backfill_twitter&amp;#39;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">filename&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">twitter_backup&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">filename&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">read_csv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">twitter_backup&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_datetime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> tweets found.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">to_delete&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strptime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">date&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)][&lt;/span>&lt;span class="s1">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">values&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Deleting &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">to_delete&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> tweets from before &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">date&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">tweet_id&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">to_delete&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">destroy_status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tweet_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="n">tweepy&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TweepError&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Finally, I prep it for command-line execution. I add two flags/arguments: a boolean for backfilling (&lt;code>-b&lt;/code>), and a string date for the oldest tweet you want to keep (&lt;code>-d&lt;/code>). The default will be anything older than 30 days. This means that, if I go quiet on Twitter and I let the bot run, it&amp;rsquo;ll clean out my timeline entirely. Which is fine (but I might want to have it leave a little note there, then, &amp;ldquo;This timeline has been archived by a bot. Angela will return soon&amp;rdquo; etc etc).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">parser&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argparse&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ArgumentParser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">description&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;Blue bird killer.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">parser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;-b&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">action&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;store_true&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dest&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;backfill&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">help&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;Backup all tweets?&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">parser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;-d&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dest&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">help&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;Delete tweets before this date (&amp;#34;YYYY-MM-DD&amp;#34;) (Default is anything older than 30 days).&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">parser&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">parse_args&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">backfill&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">backfill&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">date&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delete_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">args&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">date&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delete_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">timedelta&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">30&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">delete_old_tweets&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">delete_date&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;br>
&lt;h2 class="relative group">Thoughts
&lt;div id="thoughts" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#thoughts" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>My main sticking point was, as always: &lt;strong>abstraction&lt;/strong>. I knew I wanted to: (1) archive before I delete, but (2) not archive the entire timeline every time, and (3) delete based on the Twitter object&amp;rsquo;s ID.&lt;/p>
&lt;p>Koyaanisqatsi was wrapping up, so I was rushing and I made a mess instead: I separated out deleting from archiving (&lt;code>backfill()&lt;/code> isn&amp;rsquo;t called in &lt;code>delete_old_tweets()&lt;/code>, and I think that makes sense&amp;hellip;), but I made a mess with the filenames and duplicate deleting. If you backfill on &lt;code>2018-01-02&lt;/code> and want to delete tweets tomorrow, what filename do you choose? For now, I just choose any old archive filename, ignoring the date. Silly! Also, an archive csv is the snapshot of your entire timeline on that date - so if an archive is used for deleting more than once, you&amp;rsquo;ll run into an error: you&amp;rsquo;ll be trying to delete tweets you already deleted!&lt;/p>
&lt;p>Much better would be a living archive, one with a &lt;code>status&lt;/code> field that gets toggled: &lt;code>deleted&lt;/code>, &lt;code>live&lt;/code>, whatever. I guess I could set up a MySQL database or something? Or write over the csv when I delete? I don&amp;rsquo;t like either idea; one seems like overkill, the other seems brittle.&lt;/p>
&lt;h2 class="relative group">TODO
&lt;div id="todo" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#todo" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I could set up a cron job to run this locally, a la &lt;a href="http://angelaambroz.com/blog/posts/2017/Dec/12/automatic_desktop_backgrounds/" target="_blank">my automatic desktops script&lt;/a>. I could put it on some server somewhere; buy some space on an AWS EC2 instance. I could (finally) set up my little Raspberry Pi and have it always-on. Or I could just manually run the script as I remember to (WORST OPTION).&lt;/p>
&lt;p>For now, though, I&amp;rsquo;m happy with having a functional bot that only took about a Glass album to write (apparently about an hour).&lt;/p>
&lt;h2 class="relative group">Favorite track from Koyaanisqatsi
&lt;div id="favorite-track-from-koyaanisqatsi" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#favorite-track-from-koyaanisqatsi" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://open.spotify.com/track/2CJkP8o9kR2ICp80k27KnO" target="_blank">Prophecies&lt;/a>!&lt;/p>
&lt;h2 class="relative group">Readings
&lt;div id="readings" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#readings" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-create-a-twitter-app" target="_blank">Digital Ocean: How To Create a Twitter App&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-create-a-twitterbot-with-python-3-and-the-tweepy-library" target="_blank">Digital Ocean: How To Create a Twitterbot with Python 3 and the Tweepy Library&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://stackoverflow.com/questions/14192155/twitter-api-not-showing-old-tweets" target="_blank">StackOverflow: Twitter API not showing old tweets?
&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://stackoverflow.com/questions/42225364/getting-whole-user-timeline-of-a-twitter-user" target="_blank">StackOverflow: Getting whole user timeline of a Twitter user
&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Drawing- Anxiety</title><link>https://www.angelaambroz.com/posts/drawing_anxiety/</link><pubDate>Sun, 31 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/drawing_anxiety/</guid><description>&lt;p>Happy with:&lt;/p>
&lt;ul>
&lt;li>Right arm + hand&lt;/li>
&lt;li>Squishiness of the tentacles&lt;/li>
&lt;li>Shading&lt;/li>
&lt;li>Coloring (esp. the blushing)&lt;/li>
&lt;li>Movement quivers&lt;/li>
&lt;/ul>
&lt;p>Unhappy with:&lt;/p>
&lt;ul>
&lt;li>Left arm + hand&lt;/li>
&lt;li>Skull crush not gory/body horror enough&lt;/li>
&lt;li>Mouth and nose are very lazy&lt;/li>
&lt;li>Weird body position in general&lt;/li>
&lt;/ul>
&lt;p>Inspired a little bit by &lt;a href="http://www.newcastlenow.org/images/articles/8-1aNastThey_are_swallowing_each_other_thumb.jpg" target="_blank">Thomas Nast political cartoons&lt;/a>.&lt;/p></description></item><item><title>Clojure + cryptography = maximum fun</title><link>https://www.angelaambroz.com/posts/clojure__cryptography__maximum_fun/</link><pubDate>Fri, 29 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/clojure__cryptography__maximum_fun/</guid><description>&lt;p>In March 2017, I attended the Boston &lt;a href="http://www.clojurebridge.org/" target="_blank">ClojureBridge&lt;/a>. &lt;a href="https://clojure.org/" target="_blank">Clojure&lt;/a> is a functional programming language; it&amp;rsquo;s a dialect of &lt;a href="https://en.wikipedia.org/wiki/Lisp_%28programming_language%29" target="_blank">Lisp&lt;/a>, written on top of the &lt;a href="https://en.wikipedia.org/wiki/Java_virtual_machine" target="_blank">Java Virtual Machine&lt;/a>. In October 2017, I attended &lt;a href="http://2017.clojure-conj.org/" target="_blank">Clojure/conj&lt;/a> in Baltimore. I don&amp;rsquo;t really use Clojure in my day-to-day programming (yet!), but I&amp;rsquo;ve definitely been flirting with it for a while now.&lt;/p>
&lt;p>The tldr on why Clojure has been interesting and useful to me is:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>A different programming paradigm&lt;/strong>. I learned languages in the following order: &lt;a href="https://www.stata.com/" target="_blank">Stata&lt;/a> -&amp;gt; &lt;a href="https://www.javascript.com/" target="_blank">JavaScript&lt;/a> -&amp;gt; &lt;a href="https://www.python.org/" target="_blank">Python&lt;/a>. I&amp;rsquo;ve been resting comfortably in PythonLand since 2014. It&amp;rsquo;s a wonderful place to be. But it&amp;rsquo;s also, ya know, only one way of doing things! ClojureBridge exposed me to a totally different way of conceiving of code. The ideas of an &lt;strong>immutable state&lt;/strong>, of &lt;strong>everything as a function&lt;/strong>, of &lt;strong>functions as arguments&lt;/strong>, and even just the damn parentheses, were mind-bending and amazing. It&amp;rsquo;s helped me write better Python.&lt;/li>
&lt;li>&lt;strong>Exposure to more machine&lt;/strong>. Since I don&amp;rsquo;t have a degree in computer science (yet!), there&amp;rsquo;s a whole big wide world out there in The Machine. I didn&amp;rsquo;t really know anything about compilers until watching a couple lectures of &lt;a href="https://cs50.harvard.edu/" target="_blank">CS50&lt;/a> and writing a bit of &lt;code>C&lt;/code>. I still don&amp;rsquo;t know much! Like, I don&amp;rsquo;t really know what the JVM &lt;em>is&lt;/em>. So Clojure is a fun way for me to explore!&lt;/li>
&lt;li>&lt;strong>Ground floor data science&lt;/strong>. Several Clojure/conj speakers talked a big game about how Clojure (or functional programming, anyway) and deep learning are &lt;a href="https://www.youtube.com/watch?v=kkJNOxWPWUA" target="_blank">a, ahem, match made in heaven&lt;/a>. This was super interesting! Most of the Clojure deep learning, stats and machine learning libraries are still a bit alpha, but it was great to see the enthusiasm. And writing stuff from scratch is the best way to really learn and understand something (see below&amp;hellip;).&lt;/li>
&lt;/ol>
&lt;p>Anyway, I wanted to write up my ClojureBridge notes because I ended up FALLING IN LOVE with the project from that day: some simple cryptography tasks. CRYPTOGRAPHY IS AMAZING, PEOPLE!&lt;/p>
&lt;hr>
&lt;h2 class="relative group">Whirlwind Clojure syntax
&lt;div id="whirlwind-clojure-syntax" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#whirlwind-clojure-syntax" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Everything is a function. Some functions are built-in (like &lt;code>+&lt;/code>). Everything is parentheses. PARENS!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-clojure" data-lang="clojure">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">; This is a comment&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">;; This too&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">; General syntax&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="nf">function&lt;/span> &lt;span class="nv">arg1&lt;/span> &lt;span class="nv">arg2&lt;/span> &lt;span class="nv">..&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">; Example&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="nb">+ &lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">&amp;gt;&amp;gt;&lt;/span> &lt;span class="mi">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">; Defining a variable (evaluated only once)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">answer&lt;/span> &lt;span class="mi">42&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">; Defining a function (evaluated every time code is run)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">hello-world&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nv">name&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">println &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">str &lt;/span>&lt;span class="s">&amp;#34;Hello, &amp;#34;&lt;/span> &lt;span class="nb">name &lt;/span> &lt;span class="s">&amp;#34;!&amp;#34;&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">; Printing a docstring&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="nb">doc &lt;/span>&lt;span class="nv">func-name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 class="relative group">Project: Cryptography
&lt;div id="project-cryptography" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#project-cryptography" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The day&amp;rsquo;s project (&lt;a href="https://github.com/clojurebridge-boston/track2-ciphers" target="_blank">github/track2-ciphers&lt;/a>) was written by &lt;a href="http://cda.morris.umn.edu/~elenam/" target="_blank">Elena Machkasova&lt;/a> - thank you, Elena! The project takes you through some basic cryptography tools and puzzles: specifically, you write functions to encrypt/decrypt texts using both the &lt;a href="https://en.wikipedia.org/wiki/Caesar_cipher" target="_blank">Caesar cipher&lt;/a> and the &lt;a href="https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher" target="_blank">Vigenère cipher&lt;/a>. It also touches on cryptanalysis using frequency analysis. In the end, Elena presents an encrypted text, and you try to Clojure your way to a solution.&lt;/p>
&lt;p>It took me about ~15 hours to crack the final puzzle; 4 of them were at the actual ClojureBridge workshop in Boston, where I bumbled through Clojure and then got pretty tired by the afternoon, and the remaining 9 hours were me at home, puttering away for a few more evenings. Decrypting was &lt;em>hard&lt;/em>, but SO FUN too. And the whole journey was FANTASTIC. I loved learning about Clojure, and I loved learning about cryptography - something I apparently love!? It was like the Platonic ideal of a day-long workshop. I felt super inspired by the end, and like I had enough tools and a motivating project to continue.&lt;/p>
&lt;p>I&amp;rsquo;ll go through my method, with some notes on both Clojure the language and cryptography the mission.&lt;/p>
&lt;h3 class="relative group">Caesar cipher: Encryption and decryption
&lt;div id="caesar-cipher-encryption-and-decryption" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#caesar-cipher-encryption-and-decryption" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>The Caesar cipher replaces each letter with the letter &lt;code>n&lt;/code> places to the left. You select your &lt;code>n&lt;/code> and that&amp;rsquo;s your encryption key. To decrypt, just shift everything &lt;code>n&lt;/code> steps to the right. For example, if we choose a key of 2, we shift everything to the left by 2 steps and get an alphabet like so:&lt;/p>
&lt;pre tabindex="0">&lt;code>PLAIN: abcdefghijklmnopqrstuvwxyz
CIPHER: cdefghijklmnopqrstuvwxyzab
PLAIN: hello, world!
CIPHER: jgnnq, yqtnf!
&lt;/code>&lt;/pre>&lt;p>If you choose a key greater than 26, you can divide by 26 and use the remainder. That is, modulo 26.&lt;/p>
&lt;p>Here&amp;rsquo;s a Caesar cipher in Clojure:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-clojure" data-lang="clojure">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">;; Return the ASCII position of the first letter of the alphabet, A&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">ascii-a&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">int &lt;/span>&lt;span class="sc">\a&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">abs-value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">x&lt;/span> &lt;span class="nv">y&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">if &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">&amp;gt; &lt;/span>&lt;span class="nv">x&lt;/span> &lt;span class="nv">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">- &lt;/span>&lt;span class="nv">x&lt;/span> &lt;span class="nv">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">- &lt;/span>&lt;span class="nv">y&lt;/span> &lt;span class="nv">x&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">to-int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;takes a lowercase letter character and returns its position in the alphabet: a = 0, b = 1, etc.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">c&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">- &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">int &lt;/span>&lt;span class="nv">c&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">ascii-a&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">to-char&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;take a number and return the lowercase letter character that it refers to&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">num&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">abs_num&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">abs-value&lt;/span> &lt;span class="nv">num&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nf">if&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">&amp;lt;= &lt;/span>&lt;span class="nv">abs_num&lt;/span> &lt;span class="mi">25&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">char &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">+ &lt;/span>&lt;span class="nv">abs_num&lt;/span> &lt;span class="nv">ascii-a&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">println &lt;/span>&lt;span class="s">&amp;#34;Warning: Number must be between 0 and 25 (inclusive)&amp;#34;&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">shift&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;shifting a letter to the left by the key&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">char &lt;/span>&lt;span class="nv">key&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nf">to-char&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">mod&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">+ &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">to-int&lt;/span> &lt;span class="nv">char&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">key&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="mi">26&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">caesar-encrypt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;encrypt a word with a key using Caesar cipher&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">word&lt;/span> &lt;span class="nv">key&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">apply str &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">mapv&lt;/span> &lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">shift&lt;/span> &lt;span class="nv">%&lt;/span> &lt;span class="nv">key&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">word&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">caesar-decrypt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">word&lt;/span> &lt;span class="nv">key&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nf">caesar-encrypt&lt;/span> &lt;span class="nv">word&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">* key &lt;/span>&lt;span class="mi">-1&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;h3 class="relative group">Cracking the Caesar cipher
&lt;div id="cracking-the-caesar-cipher" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#cracking-the-caesar-cipher" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>The Caesar cipher is pretty straightforward to crack. One way would be to just try all 25 possible keys (1 - 25). Even if the encryption key was originally &amp;gt;26, the decryption key will be modulo 26 of it.&lt;/p>
&lt;p>Another way, if you don&amp;rsquo;t want to brute force it, is to conduct frequency analysis. Letters don&amp;rsquo;t appear randomly in a language; they have distinct frequencies. In English, &lt;code>e&lt;/code>, &lt;code>t&lt;/code> and &lt;code>a&lt;/code> occur way more often than letters like &lt;code>x&lt;/code>, &lt;code>q&lt;/code> and &lt;code>z&lt;/code>.&lt;/p>
&lt;p>
&lt;figure>
&lt;img class="my-0 rounded-md" loading="lazy" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/English_letter_frequency_%28frequency%29.svg/600px-English_letter_frequency_%28frequency%29.svg.png" alt="letter frequency/en" />
&lt;/figure>
&lt;/p>
&lt;p>&amp;ndash; &lt;a href="https://en.wikipedia.org/wiki/Letter_frequency#Relative_frequencies_of_letters_in_the_English_language" target="_blank">Letter frequency in the English language&lt;/a>&lt;/p>
&lt;p>If your ciphertext is long enough, you could conduct frequency analysis and compare the resulting frequencies to the plaintext English letter frequency above. Like, you could run a &lt;a href="https://en.wikipedia.org/wiki/Chi-squared_test" target="_blank">Chi-square test&lt;/a> for comparing whether two discrete distributions are the same.&lt;/p>
&lt;p>Side note but this was SUPER GLORIOUS to me! What an amazing use of statistics! I felt like John Nash in that &lt;a href="https://www.youtube.com/watch?v=U68B0MW4GIA" target="_blank">touching scene in A Beautiful Mind&lt;/a> where he exclaims, astonished, &amp;ldquo;I would never have thought of that!&amp;rdquo; when the Nobel Prize guy tells him of all the amazing uses of Nash equilibria. (And, yes, they are pretty wild - &lt;a href="https://en.wikipedia.org/wiki/Evolutionarily_stable_strategy" target="_blank">behavioral ecology&lt;/a>?! &lt;a href="https://archive.uea.ac.uk/~zzq12vpu/cancer.html" target="_blank">cancer&lt;/a>?!)&lt;/p>
&lt;p>Also, side side note but Nash - of course - did a lot of crypto. GLORIOUS CRYPTO HISTORY!&lt;/p>
&lt;h2 class="relative group">Vigenère cipher
&lt;div id="vigen%C3%A8re-cipher" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#vigen%C3%A8re-cipher" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The Vigenère cipher is an extension of the Caesar cipher. Well, sorta. Instead of choosing a key, &lt;code>n&lt;/code>, which we shift alphabet letters by, we instead choose a key phrase (a password, if you will&amp;hellip;) and use that to jumble up our plaintext. Specifically, the password letters are added to the plaintext letters; that sum is the ciphertext.&lt;/p>
&lt;pre tabindex="0">&lt;code>PLAIN: abcdefghijklmnopqrstuvwxyz
KEY: passwordpasswordpasswordpa
CIPHER: pbuvatxkxjcdibfsfrklqjnanz
&lt;/code>&lt;/pre>&lt;p>And in Clojure:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-clojure" data-lang="clojure">&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">encrypt-letter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Add two letter&amp;#39;s alpha positions together, convert that sum to new letter&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">c1&lt;/span> &lt;span class="nv">c2&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">summed&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">reduce + &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">mapv&lt;/span> &lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">to-int&lt;/span> &lt;span class="nv">%&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nv">c1&lt;/span> &lt;span class="nv">c2&lt;/span>&lt;span class="p">])))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nf">to-char&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">mod&lt;/span> &lt;span class="nv">summed&lt;/span> &lt;span class="mi">26&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">decrypt-letter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Subtract two letter&amp;#39;s alpha positions together, convert that difference to new letter&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">c1&lt;/span> &lt;span class="nv">c2&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">subbed&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">reduce - &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">mapv&lt;/span> &lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">to-int&lt;/span> &lt;span class="nv">%&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="nv">c1&lt;/span> &lt;span class="nv">c2&lt;/span>&lt;span class="p">])))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nf">to-char&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">mod&lt;/span> &lt;span class="nv">subbed&lt;/span> &lt;span class="mi">26&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">vigenere-encrypt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Cycling through a keyword, encrypt by summing the plaintext letter + keyword letter&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">text&lt;/span> &lt;span class="nv">keyword&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">clean_text&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">get-letters&lt;/span> &lt;span class="nv">text&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">apply str &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">mapv&lt;/span> &lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">encrypt-letter&lt;/span> &lt;span class="nv">%1&lt;/span> &lt;span class="nv">%2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">cycle &lt;/span>&lt;span class="nv">keyword&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">clean_text&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">vigenere-decrypt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Cycling through a keyword, decrypt by subtracting the plaintext letter + keyword letter&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">text&lt;/span> &lt;span class="nv">keyword&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">apply str &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">mapv&lt;/span> &lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">decrypt-letter&lt;/span> &lt;span class="nv">%1&lt;/span> &lt;span class="nv">%2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">text&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">cycle &lt;/span>&lt;span class="nv">keyword&lt;/span>&lt;span class="p">))))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;br>
&lt;h3 class="relative group">Cracking the Vigenère cipher
&lt;div id="cracking-the-vigen%C3%A8re-cipher" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#cracking-the-vigen%C3%A8re-cipher" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Cracking the Vigenère cipher is similar to cracking the Caesar cipher: frequency analysis. (There&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher#Cryptanalysis" target="_blank">other methods&lt;/a>, but I haven&amp;rsquo;t worked through them yet.) This only works if you have:&lt;/p>
&lt;ol>
&lt;li>Some idea of how long the key phrase is. (Otherwise, you could be conducting freq analysis for a very long time indeed.)&lt;/li>
&lt;li>A ciphertext that is pretty long. (Otherwise, your sample size will be too small and your freq analysis too noisy.)&lt;/li>
&lt;/ol>
&lt;p>In Elena&amp;rsquo;s example, she gave us two hints: the key phrase was between 2 and 8, and the ciphertext was related to ClojureBridge. She also gave a great guide on &lt;a href="https://github.com/clojurebridge-boston/track2-ciphers/blob/master/docs/track2-vigenere.md#breaking-vigenere-cipher" target="_blank">why subsequence frequency analysis works&lt;/a> - this blew my mind.&lt;/p>
&lt;p>Trying to explain it back to myself, I broke down my cryptanalysis into these steps:&lt;/p>
&lt;ul>
&lt;li>You guess a key of length &lt;code>n&lt;/code> (e.g. &lt;code>[k, e, y]&lt;/code> would have length, &lt;code>n = 3&lt;/code>), and break up your ciphertext into &lt;code>n&lt;/code> subsequences.&lt;/li>
&lt;li>Each subsequence is all the letters that &lt;em>that&lt;/em> key character (e.g. &lt;code>k&lt;/code>) is encrypting.&lt;/li>
&lt;li>Use the Chi-square test to check whether the distribution of letters in your subsequence is similar to the English language. If you see a near uniform distribution of letter frequencies, it’s probably the wrong &lt;code>n&lt;/code> - that is, if you just got random mush back, you didn&amp;rsquo;t pick the right key length. Start again.&lt;/li>
&lt;li>If you &lt;em>do&lt;/em> see patterns in your subsequences&amp;rsquo; histograms, then you can check the Caesar encryption distance between the most frequent letter in your subsequence and the most frequent letters in English (&lt;code>e, t, a&lt;/code>). You then take the subsequence of the nth+1-th letters, and predict which letter the next character in key (&lt;code>[k,e,y]&lt;/code> -&amp;gt; &lt;code>e&lt;/code>) is.&lt;/li>
&lt;li>You put together all the most-frequent-letters by subspace into your &lt;code>n&lt;/code>-length key (which should, hopefully, sound like a word).&lt;/li>
&lt;li>Then you apply your key to decrypt the entire text.&lt;/li>
&lt;/ul>
&lt;p>(This speaks to the value of long passwords and the inherent insecurity of having lots of data about ourselves out there. The longer your key phrase, the smaller the subsequences, the noisier the frequency analysis. The more encrypted data you put out there about yourself, the more data is available for cryptanalysis. I know the Vigenère cipher isn&amp;rsquo;t how modern encryption works, but the general principle did give me pause.)&lt;/p>
&lt;p>And in Clojure:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-clojure" data-lang="clojure">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">count-letters&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Count the number of times a letter, char, occurs in a string, s&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">char &lt;/span>&lt;span class="nv">s&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">count &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">filterv&lt;/span> &lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">= char &lt;/span>&lt;span class="nv">%&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">s&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">freq&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Return frequencies of each letter in a string, s&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">s&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">zipmap &lt;/span>&lt;span class="nv">alphabet&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">map &lt;/span>&lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">count-letters&lt;/span> &lt;span class="nv">%&lt;/span> &lt;span class="nv">s&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">alphabet&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">freqs&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Sort letter frequencies (desc) in a string, s&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">s&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">sort-by second &amp;gt; &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">freq&lt;/span> &lt;span class="nv">s&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">take-nth&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Split text, s, into subsequences of every n letter&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">n&lt;/span> &lt;span class="nv">s&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">take &lt;/span>&lt;span class="nv">n&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">freqs&lt;/span> &lt;span class="nv">s&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">chi-square&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Taking the observed freq hash, obs, and compute Pearson coeff (lower is better) against English lang freqs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">obs&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">exp&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">hash-map &lt;/span>&lt;span class="sc">\e&lt;/span> &lt;span class="mf">12.702&lt;/span>, &lt;span class="sc">\t&lt;/span> &lt;span class="mf">9.056&lt;/span>, &lt;span class="sc">\a&lt;/span> &lt;span class="mf">8.167&lt;/span>, &lt;span class="sc">\o&lt;/span> &lt;span class="mf">7.507&lt;/span>, &lt;span class="sc">\i&lt;/span> &lt;span class="mf">6.966&lt;/span>, &lt;span class="sc">\n&lt;/span> &lt;span class="mf">6.749&lt;/span>, &lt;span class="sc">\s&lt;/span> &lt;span class="mf">6.327&lt;/span>, &lt;span class="sc">\h&lt;/span> &lt;span class="mf">6.094&lt;/span>, &lt;span class="sc">\r&lt;/span> &lt;span class="mf">5.987&lt;/span>, &lt;span class="sc">\d&lt;/span> &lt;span class="mf">4.253&lt;/span>, &lt;span class="sc">\l&lt;/span> &lt;span class="mf">4.025&lt;/span>, &lt;span class="sc">\c&lt;/span> &lt;span class="mf">2.782&lt;/span>, &lt;span class="sc">\u&lt;/span> &lt;span class="mf">2.758&lt;/span>, &lt;span class="sc">\m&lt;/span> &lt;span class="mf">2.406&lt;/span>, &lt;span class="sc">\w&lt;/span> &lt;span class="mf">2.360&lt;/span>, &lt;span class="sc">\f&lt;/span> &lt;span class="mf">2.228&lt;/span>, &lt;span class="sc">\g&lt;/span> &lt;span class="mf">2.015&lt;/span>, &lt;span class="sc">\y&lt;/span> &lt;span class="mf">1.974&lt;/span>, &lt;span class="sc">\p&lt;/span> &lt;span class="mf">1.929&lt;/span>, &lt;span class="sc">\b&lt;/span> &lt;span class="mf">1.492&lt;/span>, &lt;span class="sc">\v&lt;/span> &lt;span class="mf">0.978&lt;/span>, &lt;span class="sc">\k&lt;/span> &lt;span class="mf">0.772&lt;/span>, &lt;span class="sc">\j&lt;/span> &lt;span class="mf">0.153&lt;/span>, &lt;span class="sc">\x&lt;/span> &lt;span class="mf">0.150&lt;/span>, &lt;span class="sc">\q&lt;/span> &lt;span class="mf">0.095&lt;/span>, &lt;span class="sc">\z&lt;/span> &lt;span class="mf">0.074&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">e&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">vals &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">sort-by first &lt;/span>&lt;span class="nv">exp&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">o&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">vals &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">sort-by first &lt;/span>&lt;span class="nv">obs&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">subtracts&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">map &lt;/span>&lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">- &lt;/span>&lt;span class="nv">%1&lt;/span> &lt;span class="nv">%2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">o&lt;/span> &lt;span class="nv">e&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">squares&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">map &lt;/span>&lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">* &lt;/span>&lt;span class="nv">%&lt;/span> &lt;span class="nv">%&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">subtracts&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">normed&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">map &lt;/span>&lt;span class="o">#&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">/ &lt;/span>&lt;span class="nv">%1&lt;/span> &lt;span class="nv">%2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">squares&lt;/span> &lt;span class="nv">e&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">reduce + &lt;/span>&lt;span class="nv">normed&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="kd">defn &lt;/span>&lt;span class="nv">try-key&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Given an encrypted text, text, try a key of lenth n and return Chi-square test&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nv">text&lt;/span> &lt;span class="nv">n&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">every-nth-letter&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">take-nth &lt;/span>&lt;span class="nv">n&lt;/span> &lt;span class="nv">text&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">freq-every-nth&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">freqs&lt;/span> &lt;span class="nv">every-nth-letter&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="k">def &lt;/span>&lt;span class="nv">freq-hash&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">freq_hash&lt;/span> &lt;span class="nv">freq-every-nth&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nf">chi-square&lt;/span> &lt;span class="nv">freq-hash&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Honestly, I haven&amp;rsquo;t looked at this code in a couple months, and it&amp;rsquo;s a &lt;em>mess&lt;/em>. One thing I need to learn is organizing a Clojure project. For now, though, I just manually ran through &lt;code>try-key&lt;/code> with the key lengths between 2 and 8, and noted down, first, whether it looked like non-mush came back and, if so, what the likely key character was.&lt;/p>
&lt;p>I did this until I had a key length and key that looked reasonable, and then I checked it against the encrypted exercise text. When it worked, it was AMAZING!&lt;/p>
&lt;p>This manual method was not great, though, since my human brain is a pattern-recognition machine, and so I saw a lot of patterns that weren&amp;rsquo;t there. Automating it more would have probably helped in avoiding false-positive traps that my brain kept laying, as well as removing some of the general manual pain.&lt;/p></description></item><item><title>Drawing- My commute</title><link>https://www.angelaambroz.com/posts/drawing_my_commute/</link><pubDate>Fri, 29 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/drawing_my_commute/</guid><description>&lt;p>Today&amp;rsquo;s commute included:&lt;/p>
&lt;ul>
&lt;li>The next few chapters of Tony Judt&amp;rsquo;s &lt;a href="https://www.goodreads.com/book/show/29658.Postwar" target="_blank">Postwar&lt;/a> (audiobook). Today&amp;rsquo;s chapters focused on 1956: specifically, the Suez Canal crisis and the Hungarian revolt.&lt;/li>
&lt;li>Sub-freezing temps.&lt;/li>
&lt;/ul>
&lt;h3 class="relative group">Pencil sketch
&lt;div id="pencil-sketch" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#pencil-sketch" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;h3 class="relative group">Inked
&lt;div id="inked" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#inked" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;h3 class="relative group">Final
&lt;div id="final" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#final" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Still looking for a style that I like. I&amp;rsquo;ve been stuck on this current &amp;ldquo;art skills&amp;rdquo; plateau for a loooong time (10+ years). But I also haven&amp;rsquo;t really been drawing/arting for 10+ years. So I have hope!&lt;/p></description></item><item><title>TIL- Multiple cursors in Jupyter</title><link>https://www.angelaambroz.com/posts/til_multiple_cursors_in_jupyter/</link><pubDate>Thu, 28 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/til_multiple_cursors_in_jupyter/</guid><description>&lt;p>&lt;a href="http://www.perfectlyrandom.org/2016/03/19/sublime-text-style-multiple-cursors-in-jupyter-notebook/" target="_blank">This tutorial by perfectlyrandom.org&lt;/a> had been on my TODO list for about 5 months. Today I finally did it! Jeez. I basically failed productivity hacking. Anyway.&lt;/p>
&lt;p>&lt;span class="caption">&lt;a href="https://xkcd.com/1205/" target="_blank">xkcd/1205&lt;/a>&lt;/span>&lt;/p>
&lt;h2 class="relative group">Multiple cursors are great
&lt;div id="multiple-cursors-are-great" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#multiple-cursors-are-great" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Multiple cursors are great, and they&amp;rsquo;re available (mostly by default) in a lot of text editors: &lt;a href="https://www.sublimetext.com/3" target="_blank">Sublime&lt;/a>, &lt;a href="https://atom.io/" target="_blank">Atom&lt;/a>, &lt;a href="https://www.jetbrains.com/pycharm/" target="_blank">PyCharm&lt;/a>. They are a yuuuge part of my daily productivity. I don&amp;rsquo;t know what I&amp;rsquo;d do without them.&lt;/p>
&lt;p>Except that, until now, I had indeed been surviving without them in my &lt;em>other&lt;/em> main window of choice: the browser-based Jupyter notebook. Until now. UNTIL NOW!&lt;/p>
&lt;h2 class="relative group">TLDR tutorial
&lt;div id="tldr-tutorial" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#tldr-tutorial" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The full tutorial is &lt;a href="http://www.perfectlyrandom.org/2016/03/19/sublime-text-style-multiple-cursors-in-jupyter-notebook/" target="_blank">here&lt;/a>. But here&amp;rsquo;s the &lt;code>tldr&lt;/code> of what I did:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/.jupyter
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir custom
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">subl custom/custom.js
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then, once in &lt;code>custom.js&lt;/code>, this worked for me (it&amp;rsquo;s the &lt;a href="http://disq.us/p/1n86k3y" target="_blank">first comment&lt;/a>):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">require&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s2">&amp;#34;codemirror/keymap/sublime&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;notebook/js/cell&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;base/js/namespace&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">sublime_keymap&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">cell&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">IPython&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cell&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Cell&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">options_default&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">cm_config&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">keyMap&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;sublime&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">var&lt;/span> &lt;span class="nx">cells&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">IPython&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">notebook&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get_cells&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">c&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">c&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nx">cells&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span> &lt;span class="p">;&lt;/span> &lt;span class="nx">c&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">cells&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">c&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">code_mirror&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">setOption&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;keyMap&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;sublime&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="http://www.harkavagrant.com/index.php?id=326" target="_blank">Aw yiss.&lt;/a>&lt;/p></description></item><item><title>2017 in review- Books</title><link>https://www.angelaambroz.com/posts/2017_in_review_books/</link><pubDate>Sat, 23 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/2017_in_review_books/</guid><description>&lt;p>Meh. This year was just an okay reading year for me. At least, I felt like I read a lot of stuff which has been deeply influencing my day to day thinking (high Influence Factor!), but the Pleasure/Inspiration Factor was just okay. I mean, I &lt;em>did&lt;/em> enjoy many books this year. But none of them made me want to shriek with joy, so we&amp;rsquo;re not talking peak book joy.&lt;/p>
&lt;p>I also noticed that, this year, my reading followed a few distinct themes:&lt;/p>
&lt;ul>
&lt;li>More politics/US history books than usual. For obvious reasons.&lt;/li>
&lt;li>Less sci-fi than usual. :(&lt;/li>
&lt;li>Less graphic novels, more audiobooks.&lt;/li>
&lt;/ul>
&lt;p>Anyway, let&amp;rsquo;s begin Official Book Reflection Time.&lt;/p>
&lt;h2 class="relative group">Most pleasurable read: &lt;a href="https://www.goodreads.com/review/show/1928921222?book_show_action=false&amp;amp;from_review_page=1" target="_blank">&lt;em>The Undoing Project&lt;/em>, Michael Lewis&lt;/a>
&lt;div id="most-pleasurable-read-_the-undoing-project_-michael-lewishttpswwwgoodreadscomreviewshow1928921222book_show_actionfalsefrom_review_page1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#most-pleasurable-read-_the-undoing-project_-michael-lewishttpswwwgoodreadscomreviewshow1928921222book_show_actionfalsefrom_review_page1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Non-fiction. About the intellectual romance between the two giants of behavioral economics: Daniel Kahneman and Amos Tversky.&lt;/p>
&lt;p>I LOVE behavioral economics, and I love learning about the humans and humanity behind these big economic ideas. I had already really enjoyed Nina Munk&amp;rsquo;s &lt;a href="https://www.goodreads.com/review/show/745899185?book_show_action=false&amp;amp;from_review_page=1" target="_blank">The Idealist&lt;/a>, about Jeff Sachs and his (somewhat infamous) Millennium Villages project, and this book is in the same vein. If you already know the research, it&amp;rsquo;s catnip. If you&amp;rsquo;ve never heard of behavioral econ, I think it gives a good overview. The portrait of these two, very different individuals (it&amp;rsquo;s an odd:q
couple buddy movie!), the history of Palestine and Israel, the drama of academia. It was so good. I was especially charmed by Amos Tversky&amp;rsquo;s biting wit.&lt;/p>
&lt;h2 class="relative group">Most guilty pleasure read: &lt;a href="https://www.goodreads.com/review/show/2041368727?book_show_action=false&amp;amp;from_review_page=1" target="_blank">&lt;em>Endymion&lt;/em>, Dan Simmons&lt;/a>
&lt;div id="most-guilty-pleasure-read-_endymion_-dan-simmonshttpswwwgoodreadscomreviewshow2041368727book_show_actionfalsefrom_review_page1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#most-guilty-pleasure-read-_endymion_-dan-simmonshttpswwwgoodreadscomreviewshow2041368727book_show_actionfalsefrom_review_page1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This book has no right to be as fun as it is. It&amp;rsquo;s the third book in a four-book sci-fi series, i.e. it should be VERY BAD. The first one, &lt;a href="https://www.goodreads.com/book/show/77566.Hyperion" target="_blank">Hyperion&lt;/a>, won the Hugo &lt;em>and&lt;/em> Nebula, and it is super good. But my experience with sf series is that the quality of the sequels is inversely related to the quality of the first book. Like, exponentially. &lt;a href="https://www.goodreads.com/review/show/628832676?book_show_action=false&amp;amp;from_review_page=1" target="_blank">The Fall of Hyperion&lt;/a> (book 2) was not so bad, but I was still expecting Endymion to, well, suck.&lt;/p>
&lt;p>But it doesn&amp;rsquo;t! It&amp;rsquo;s basically glittering garbage B-grade wonderfulness. It&amp;rsquo;s no longer as mystical and awe-inspiring as Hyperion 1 and 2, instead it becomes silly and FUN. What an adventure! And, ho man, did I love Father Captain Federico de Soya, the Catholic space captain with a heart o&amp;rsquo; gold. Played by Luigi Lo Cascio in my head. Specifically Luigi Lo Cascio at &lt;a href="https://youtu.be/jLxRVhIwC_k?t=30s" target="_blank">0:30 in the &lt;em>Noi Credevamo&lt;/em> trailer&lt;/a>. SPACE CATHOLIC CAPTAIN FROM ITALIA! (He&amp;rsquo;s actually Spanish, but whatevs.)&lt;/p>
&lt;h2 class="relative group">Book that made me reevaluate fiction as an art form: &lt;a href="https://www.goodreads.com/review/show/1869810529?book_show_action=false&amp;amp;from_review_page=1" target="_blank">&lt;em>Americanah&lt;/em>, Chimamanda Ngozi Adichie&lt;/a>
&lt;div id="book-that-made-me-reevaluate-fiction-as-an-art-form-_americanah_-chimamanda-ngozi-adichiehttpswwwgoodreadscomreviewshow1869810529book_show_actionfalsefrom_review_page1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#book-that-made-me-reevaluate-fiction-as-an-art-form-_americanah_-chimamanda-ngozi-adichiehttpswwwgoodreadscomreviewshow1869810529book_show_actionfalsefrom_review_page1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Sometime in ~2006, I stopped reading fiction and switched entirely to sci-fi and non-fiction. A friend of mine rightly pointed out that you kinda can&amp;rsquo;t discredit an entire art form, but I was like, NOVELS HOLD NO TRUTH, I WILL NOT WASTE MY TIME.&lt;/p>
&lt;p>Oh, how wrong I was. How wonderful Americanah is. How I laughed and cried and marveled at Adichie insight and acumen. SO GOOD.&lt;/p>
&lt;h2 class="relative group">Best graphic novel: &lt;a href="https://www.goodreads.com/review/show/1903135492?book_show_action=false&amp;amp;from_review_page=1" target="_blank">&lt;em>Sex Criminals&lt;/em>, Matt Fraction, Chip Zdarsky &lt;/a>
&lt;div id="best-graphic-novel-_sex-criminals_-matt-fraction-chip-zdarsky-httpswwwgoodreadscomreviewshow1903135492book_show_actionfalsefrom_review_page1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#best-graphic-novel-_sex-criminals_-matt-fraction-chip-zdarsky-httpswwwgoodreadscomreviewshow1903135492book_show_actionfalsefrom_review_page1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Kind of a toss-up with &lt;a href="https://www.goodreads.com/review/show/1899828007?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Bitch Planet&lt;/a>, with some of the same themes of sexuality, sexual politics, and gender. But whereas Bitch Planet is a screaming ball of fiery rage, Sex Criminals is more relaxed: it&amp;rsquo;s fun and smart and often touching. I read volumes 1 and 2 and &lt;em>loved&lt;/em> them.&lt;/p>
&lt;h2 class="relative group">Best book to understand American politics: &lt;a href="https://www.goodreads.com/review/show/2129494710?book_show_action=false&amp;amp;from_review_page=1" target="_blank">&lt;em>The Unwinding&lt;/em>, George Packer&lt;/a>
&lt;div id="best-book-to-understand-american-politics-_the-unwinding_-george-packerhttpswwwgoodreadscomreviewshow2129494710book_show_actionfalsefrom_review_page1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#best-book-to-understand-american-politics-_the-unwinding_-george-packerhttpswwwgoodreadscomreviewshow2129494710book_show_actionfalsefrom_review_page1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Okay, let me preface this by saying that I read A LOT of books about the US this year, specifically: &lt;a href="https://www.goodreads.com/review/show/2121583276?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Hillary&amp;rsquo;s campaign memoir&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/2163497372?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Katy Tur&amp;rsquo;s campaign memoir&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/2182127931?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Alyssa Mastromonaco&amp;rsquo;s White House memoir&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/1785585891?book_show_action=false&amp;amp;from_review_page=1" target="_blank">John Dickerson&amp;rsquo;s book about campaigns&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/2130566932?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Ta-Nehisi Coates&amp;rsquo;s Obama memoir&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/2203160796?book_show_action=false&amp;amp;from_review_page=1" target="_blank">a book about White House Chiefs of Staff&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/2032564483?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Al Franken&amp;rsquo;s campaign memoir&lt;/a> (cringe&amp;hellip;), and a &lt;a href="https://www.goodreads.com/review/show/2001580018?book_show_action=false&amp;amp;from_review_page=1" target="_blank">huge tome about 17th century English migration patterns to the US and how that explains all of modern American politics&lt;/a>. So&amp;hellip; a LOT OF COMMENTARY on the whole Trump stuff. I&amp;rsquo;m also reading &lt;a href="https://www.goodreads.com/book/show/29658.Postwar?ac=1&amp;amp;from_search=true" target="_blank">Postwar&lt;/a> now, about Europe after WW2, and that&amp;rsquo;s informing how I see the US political moment.&lt;/p>
&lt;p>But &lt;em>none&lt;/em> of them had me as horrified or as certain as George Packer&amp;rsquo;s The Unwinding. Reading that, Trump&amp;rsquo;s election and the rise of know-nothing populism seems inevitable. It&amp;rsquo;s told as a series of insightful, humanistic mini-biographies about Americans both famous and everyday. And it&amp;rsquo;s an incredible portrait of how our politics and culture have changed in the last thirty years.&lt;/p>
&lt;h2 class="relative group">&amp;hellip;and happiness chaser: Best Kim Stanley Robinson book from this year: &lt;a href="https://www.goodreads.com/review/show/2138432370?book_show_action=false&amp;amp;from_review_page=1" target="_blank">&lt;em>The Years of Rice and Salt&lt;/em>&lt;/a>
&lt;div id="and-happiness-chaser-best-kim-stanley-robinson-book-from-this-year-_the-years-of-rice-and-salt_httpswwwgoodreadscomreviewshow2138432370book_show_actionfalsefrom_review_page1" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#and-happiness-chaser-best-kim-stanley-robinson-book-from-this-year-_the-years-of-rice-and-salt_httpswwwgoodreadscomreviewshow2138432370book_show_actionfalsefrom_review_page1" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Super Buddhist mystical reincarnation adventure through a crazy epic alt history, WHAT&amp;rsquo;S NOT TO LOVE!?&lt;/p></description></item><item><title>Data is my co-pilot</title><link>https://www.angelaambroz.com/posts/data_is_my_copilot/</link><pubDate>Thu, 21 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/data_is_my_copilot/</guid><description>&lt;p>Article report time! Today I read this, &lt;a href="https://www.nature.com/articles/d41586-017-07522-z" target="_blank">Five Ways to Fix Statistics, &lt;em>Nature&lt;/em> (Nov 2017)&lt;/a>. It interviews six statistics luminaries about what&amp;rsquo;s &amp;ldquo;wrong&amp;rdquo; with modern statistics. Here are some choice quotes (&lt;strong>all emphasis mine&lt;/strong>):&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;In the past couple of decades, many fields have shifted from data sets with a dozen measurements to data sets with millions. &lt;strong>Methods that were developed for a world with sparse and hard-to-collect information have been jury-rigged to handle bigger, more-diverse and more-complex data sets.&lt;/strong> No wonder the literature is now full of papers that use outdated statistics, misapply statistical tests and misinterpret results. &lt;strong>The application of P values to determine whether an analysis is interesting is just one of the most visible of many shortcomings.&lt;/strong>&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&amp;ndash; &lt;a href="http://jtleek.com/" target="_blank">Jeff Leek&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;In many fields, decisions about whether to publish an empirical finding, pursue a line of research or enact a policy are considered only when results are &amp;lsquo;statistically significant&amp;rsquo;, defined as having a P value (or similar metric) that falls below some pre-specified threshold. This approach is called null hypothesis significance testing (NHST). &lt;strong>It encourages researchers to investigate so many paths in their analyses that whatever appears in papers is an unrepresentative selection of the data.&amp;rdquo;&lt;/strong>&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&lt;em>&amp;quot;&lt;strong>Statistical-significance thresholds are perhaps useful under certain conditions: when effects are large and vary little under the conditions being studied, and when variables can be measured accurately.&lt;/strong> This may well describe the experiments for which NHST and canonical statistical methods were developed, such as agricultural trials in the 1920s and 1930s examining how various fertilizers affected crop yields. &lt;strong>Nowadays, however, in areas ranging from policy analysis to biomedicine, changes tend to be small, situation-dependent and difficult to measure.&lt;/strong> For example, in nutrition studies, it can be a challenge to get accurate reporting of dietary choices and health outcomes.&amp;quot;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&amp;ndash; &lt;a href="http://www.kellogg.northwestern.edu/faculty/directory/mcshane_blake.aspx" target="_blank">Blakeley McShane&lt;/a> &amp;amp; &lt;a href="http://andrewgelman.com/" target="_blank">Andrew Gelman&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;The plethora of options creates a hazard that statistician Andrew Gelman has dubbed the garden of forking paths, a place where people are easily led astray. In the vast number of routes, at least one will lead to a &amp;lsquo;significant&amp;rsquo; finding simply by chance. &lt;strong>Researchers who hunt hard enough will turn up a result that fits statistical criteria — but their discovery will probably be a false positive.&lt;/strong>&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&amp;ndash; &lt;a href="https://mbnuijten.com/" target="_blank">Michèle B. Nuijten&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;blockquote>
&lt;p>&lt;em>&amp;ldquo;Norms are established within communities partly through methodological mimicry. In a paper published last month on predicting suicidality, the authors justified their sample size of 17 participants per group by stating that a previous study of people on the autism spectrum had used those numbers. Previous publication is not a true justification for the sample size, but it does legitimize it as a model. &lt;strong>To quote from a Berwick report on system change, &amp;ldquo;culture will trump rules, standards and control strategies every single time&amp;rdquo;&lt;/strong> (see &lt;a href="go.nature.com/2hxo4q2">go.nature.com/2hxo4q2&lt;/a>).&amp;rdquo;&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&amp;ndash; &lt;a href="https://profiles.stanford.edu/steven-goodman" target="_blank">Steven Goodman&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;p>The tldr is that:&lt;/p>
&lt;ul>
&lt;li>We&amp;rsquo;re too confident. We hide uncertainty. We overstate claims.&lt;/li>
&lt;li>We do that because of (a) incentive structures around academic publishing, (b) cognitive errors and bias around wanting certainty.&lt;/li>
&lt;/ul>
&lt;p>Some of the proposed solutions are:&lt;/p>
&lt;ul>
&lt;li>Trial registries like &lt;a href="https://clinicaltrials.gov/" target="_blank">ClinicalTrials.gov&lt;/a> and &lt;a href="https://www.socialscienceregistry.org/" target="_blank">the AEA RCT registry&lt;/a> (I used to work on this! oh memories).&lt;/li>
&lt;li>Changing norms around p-values for grant funding, article publication, etc.&lt;/li>
&lt;li>Accepting, with cold existential dread, that &lt;a href="http://www.hawking.org.uk/does-god-play-dice.html" target="_blank">we live in a probabilistic universe&lt;/a>.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>This article also made me think about the data science hype/bubble. Data-driven decision making is definitely preferable to, uh, gut-driven decision-making? norms-driven decision making? There&amp;rsquo;s still a lot more data out there to be scienced. So the bubble is, maybe, merited. I mean, I work in the bubble, so please please let&amp;rsquo;s keep this data thing going, okay!? But I don&amp;rsquo;t worry too much. We live in a world where enormous amounts of data are being passively generated, and this is only going to increase (exponentially?) as IoT stuff takes off. The day your WiFi-enabled fridge starts judging you will be a day of much glory for statisticians and machine learningers.&lt;/p>
&lt;p>But data literacy is so important, and so under-taught. And if my human brain understands Daniel Kahneman and Amos Tversky&amp;rsquo;s work on human brains, we are also just not great at understanding uncertainty. We want certainty - and positive results! As some colleagues used to say, half-joking, &amp;ldquo;up and to the right!&amp;rdquo; But null results are important; counter-intuitive (in a not-sexy, non-&amp;ldquo;ah ha!&amp;rdquo; way) results are important.&lt;/p>
&lt;p>I feel like, right now, there&amp;rsquo;s a lot of gatekeeping around data science as being something very complex and difficult, and a treatment that it&amp;rsquo;s a black box full of dark magic. It&amp;rsquo;s not: it&amp;rsquo;s mostly linear algebra (which you can learn &lt;a href="https://www.khanacademy.org/math/linear-algebra" target="_blank">here&lt;/a>). Worryingly, people - even fancy people - &lt;em>still&lt;/em> conflate prediction with causation. It&amp;rsquo;s not: it&amp;rsquo;s mostly correlation. Hence machine learning&amp;rsquo;s &lt;a href="https://www.propublica.org/series/machine-bias" target="_blank">infamous reputation for perpetuating bias&lt;/a>; if you don&amp;rsquo;t care to disentangle &lt;em>why&lt;/em> something worked, you&amp;rsquo;re less likely to confront ugly correlations and disentangle them for what they are.&lt;/p>
&lt;p>Anyway. Some random thoughts. I definitely recommend Joel Best&amp;rsquo;s &lt;a href="https://www.goodreads.com/book/show/51289.Damned_Lies_and_Statistics" target="_blank">Damned Lies and Statistics&lt;/a>. It&amp;rsquo;s not very technical, and is instead more interested in the history and culture of stats - something that might be just as important as the technical side.&lt;/p></description></item><item><title>I &lt;3 waves</title><link>https://www.angelaambroz.com/posts/i_heart_waves/</link><pubDate>Wed, 20 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/i_heart_waves/</guid><description>&lt;p>My formal education in physics ended in high school - what a shame!&lt;/p>
&lt;p>As an adult, I&amp;rsquo;ve had big interests in psychedelic mind-bending modern physics (Kip Thorne et al.) and early 20th century atom-splitting physics (Einstein, Oppenheimer, Bohrs, et al.). I mean, hello, &lt;a href="http://www.angelaambroz.com/scifi.html" target="_blank">sci fi&lt;/a>!&lt;/p>
&lt;p>In addition to big physics ideas, I&amp;rsquo;m also interested in the &lt;strong>humble wave&lt;/strong>. Specifically, sound waves and radio waves. (Also &lt;a href="https://www.goodreads.com/review/show/612593872?book_show_action=false&amp;amp;from_review_page=1" target="_blank">rogue ocean waves&lt;/a> and &lt;a href="https://www.goodreads.com/review/show/1707535586?book_show_action=false&amp;amp;from_review_page=1" target="_blank">surfing memoirs&lt;/a>.)&lt;/p>
&lt;p>Recently, I was noticing that my Bluetooth headphones were stuttering whenever I went jogging. They did this near certain busy intersections, and were stutter-free when I was on trails or rural roads. This got me thinking: how does Bluetooth work? How do radio waves work? Clearly it was time for a PERSONAL WAVE WORKSHOP.&lt;/p>
&lt;blockquote>
&lt;p>&amp;ldquo;Hearing&amp;rdquo; is tiny hairs in your ears being moved by sound waves. These are called &lt;a href="https://en.wikipedia.org/wiki/Stereocilia_%28inner_ear%29" target="_blank">stereocilia&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 class="relative group">Some random stuff I learned about Bluetooth
&lt;div id="some-random-stuff-i-learned-about-bluetooth" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#some-random-stuff-i-learned-about-bluetooth" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Bluetooth was developed by Ericsson in the 1990s and was named after a 10th century Viking king, &lt;a href="https://en.wikipedia.org/wiki/Harald_Bluetooth" target="_blank">Harald Blåtand Gormsen&lt;/a>, AKA King Harald Bluetooth, I am not making this up, the jokes write themselves, people.&lt;/p>
&lt;p>Blåtand was known as a bringer together of people, helping them to communicate (get it&amp;hellip;). The Bluetooth logo is made up of his initials, H and B, written in &lt;a href="https://www.google.com/search?q=Dictionary#dobs=rune" target="_blank">runes&lt;/a> - AKA ye olde Germanic script.&lt;/p>
&lt;blockquote>
&lt;p>One of the world&amp;rsquo;s biggest big wave hot spots is &lt;a href="https://en.wikipedia.org/wiki/Teahupo%27o" target="_blank">Teahupo&amp;rsquo;o&lt;/a>, Tahiti. &lt;a href="https://vimeo.com/35328567" target="_blank">Here&amp;rsquo;s some mystical big wave surfing to enjoy.&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;p>Modern Bluetooth/Blåtand operates via radio waves in the 2.40 GHz - 2.485 GHz frequency band. It has a range of ~1m (Arduino widgets?) to ~10m (my phone and headphones) to ~100m (industrial strength). It sends data in discrete packets. To avoid crowding problems, these packets can be sent along 79 &amp;ldquo;Bluetooth channels&amp;rdquo;. They &lt;a href="https://en.wikipedia.org/wiki/Frequency-hopping_spread_spectrum" target="_blank">hop around&lt;/a>, looking for the least crowded channel.&lt;/p>
&lt;h2 class="relative group">Stepping back: What&amp;rsquo;s a radio wave?
&lt;div id="stepping-back-whats-a-radio-wave" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#stepping-back-whats-a-radio-wave" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>That was my next question. Okay, so WiFi and Bluetooth are technologies that send data on radio waves. But what &lt;em>is&lt;/em> a radio wave? And how does information get encoded (in binary, I guess?) and sent along it? I &lt;a href="https://www.npr.org/2017/01/10/509035454/why-its-literally-not-wrong-to-say-literally" target="_blank">literally&lt;/a> had no idea. Here&amp;rsquo;s what I learned:&lt;/p>
&lt;p>Radio waves == electromagnetic waves, since they&amp;rsquo;re made up of electric and magnetic signals. The signals are at right angles to each other. So it&amp;rsquo;s like two waves, one electric and one magnetic, in a helix-y.&lt;/p>
&lt;p>&lt;a href="https://micro.magnet.fsu.edu/primer/java/electromagnetic/index.html" target="_blank">source&lt;/a>&lt;/p>
&lt;p>These EM waves are the same you use in your microwave, from your WiFi router, from the cell phone tower, the radio antenna and the TV antenna. And Bluetooth!&lt;/p>
&lt;p>They travel at the speed of light. You can measure the wavelength of an EM signal by dividing the frequency (e.g. 2.4 GHz for WiFi/Bluetooth) from the speed of light (299,792,458 m/s). Okay, I did this for WiFi/Bluetooth and it&amp;rsquo;s 0.12m, or 12 cm. Google says I&amp;rsquo;m right! Scientific notation for &amp;ldquo;wavelength&amp;rdquo; is $\lambda$.&lt;/p>
&lt;p>There&amp;rsquo;s a direct relationship between the wavelength and the size of the antennae - bigger (&lt;strike>slower&lt;/strike>? SPEED OF LIGHT) frequencies, like AM radio stations, have much bigger wavelengths (see equation above - the denominator shrinks, ergo the wavelength expands) and thus require LITERALLY LARGE ANTENNAS. I guess that means that our cell phone antennas, which are tiny, pick up the (&lt;strike>much faster&lt;/strike>?) EM waves of WiFi and phone signals.&lt;/p>
&lt;p>You can jack up antennas to have &amp;ldquo;gain&amp;rdquo;, which boosts the signal. This is done by manipulating the shape of the antenna. I &lt;em>think&lt;/em> this might be related to what &lt;a href="https://youtu.be/TfYCnOvNnFU?t=6m22s" target="_blank">Crash Course&lt;/a> was saying about &lt;code>constructive interference&lt;/code>, where you amplify waves.&lt;/p>
&lt;p>There are:&lt;/p>
&lt;ul>
&lt;li>&lt;code>ground waves&lt;/code>, that follow the shape of the Earth&lt;/li>
&lt;li>&lt;code>line of sight&lt;/code> waves, that get thrown off by the shape of the Earth (at the &lt;code>radio horizon&lt;/code>, new band name?)&lt;/li>
&lt;/ul>
&lt;p>Short wavelengths, like Bluetooth (!), can be absorbed by rain droplets.&lt;/p>
&lt;h2 class="relative group">Random stuff I learned about waves in general
&lt;div id="random-stuff-i-learned-about-waves-in-general" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#random-stuff-i-learned-about-waves-in-general" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;code>Frequency&lt;/code> is the number of wave cycles that occur within one second. This is measured in hertz. So 2.4 GHz - the frequency band where Bluetooth and WiFi are - is 2,400,000,000 wave, or 2.4 billion, cycles in 1 second.&lt;/li>
&lt;li>Waves carry information (through space and time!).&lt;/li>
&lt;li>Most wave equations seem pretty simple!&lt;/li>
&lt;li>Waves coming at each other in opposite directions can augment (&lt;code>constructive interference&lt;/code>) or decrease (&lt;code>destructive interference&lt;/code>) each other&amp;rsquo;s energy. This is now &lt;a href="https://youtu.be/TfYCnOvNnFU?t=6m22s" target="_blank">noise-cancelling headphones&lt;/a> work - they send out &amp;ldquo;inverse&amp;rdquo; sound waves! SO COOL!&lt;/li>
&lt;li>Sound waves don&amp;rsquo;t move perpendicular in motion (like a rope being oscillated) but in a &lt;a href="https://youtu.be/qV4lR9EWGlY?t=2m7s" target="_blank">compression-squeezing way&lt;/a> (like a spring). WHAT. Is this why, when my phone is on speaker and I have it right up in my face, I can feel small bursts of air coming from the speakers as the person on the other side talks?&lt;/li>
&lt;li>Sound perception is logarithmic, not linear, to actual loudness/intensity.&lt;/li>
&lt;li>That you can use a method developed by a guy named Huygens to figure out where a wave is going: basically, every point on a wave generates a semi-circular (semi-spherical?) &amp;lsquo;wavelet&amp;rsquo; - the line tangent to all the wavelets is where the wave will next be.&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>Colors are just light waves with different wave lengths. Red has the biggest distance between wave peaks - blue the shortest. There are &amp;ldquo;colors&amp;rdquo; beyond this, in wavelengths the human eye can&amp;rsquo;t perceive. The unit measure of light wavelength is the &lt;a href="https://en.wikipedia.org/wiki/Nanometre" target="_blank">nanometer&lt;/a>, or 0.000000001 meters.&lt;/p>
&lt;/blockquote>
&lt;h2 class="relative group">Conclusion: Some hypotheses for why my Bluetooth headphones are crapping out
&lt;div id="conclusion-some-hypotheses-for-why-my-bluetooth-headphones-are-crapping-out" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#conclusion-some-hypotheses-for-why-my-bluetooth-headphones-are-crapping-out" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Action plan time!&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Bluetooth&amp;rsquo;s fault: Rain&lt;/strong>. There&amp;rsquo;s a high correlation between me running in a dense city rain, and me running on a rural road with clear skies. Just by chance. So maybe I&amp;rsquo;ve misattributed the problem to city density, and not rain, and the fact that high-frequency EM waves can be absorbed by radio droplets.
&lt;ul>
&lt;li>&lt;strong>Test&lt;/strong>: Go running in the city dense area when it&amp;rsquo;s sunny. Do this enough times for statistical significance.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Everyone else&amp;rsquo;s fault: Busy channels&lt;/strong>. Bluetooth travels along 79 channels, one for each megahertz between 2.4 GHz and 2483.5 MHz. When I run in device-dense areas, especially near intersections, all 79 channels might be maxed out.
&lt;ul>
&lt;li>&lt;strong>Test&lt;/strong>: Identify places where (I guess) the channels will be more or less crowded. Run there.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>My headphones&amp;rsquo;s fault: Antenna design&lt;/strong>. Signals have a polarity which can be horizontal, vertical, or circular. Antenna get the best signal when they&amp;rsquo;re rotated to the same axis as the polarity. If my cellphone emits, say, a horizontally-polarized signal, and my headphones are better positioned for a vertical one, I may get a worse signal.
&lt;ul>
&lt;li>&lt;strong>Test&lt;/strong>: Wear headphones and place phone at different spots around them. e.g. Above the headphones, below them, rotated, etc.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>My fault: my running pouch&lt;/strong>. It sounded like high frequency signals, such as WiFi/Bluetooth, are pretty fragile and can get disrupted more easily than long, slow, low frequency signals. While some materials (e.g. cement, trees) are known to disrupt stuff, maybe my cloth and plastic running pouch is disturbing the cell phone-headphone link.
&lt;ul>
&lt;li>&lt;strong>Test&lt;/strong>: Run with the phone in my hand.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>So I have a bunch of potential experiments now, and - given the amount that I run - my sample size won&amp;rsquo;t be big enough to detect changes for another, well, several months or so. But I have a plan! Which is awesome.&lt;/p>
&lt;h2 class="relative group">Resources
&lt;div id="resources" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#resources" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Bluetooth:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/Bluetooth" target="_blank">Wikipedia: Bluetooth&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=TXmOpc5_PO8" target="_blank">YouTube: Bluetooth Explained | All you need to know!&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://large.stanford.edu/courses/2012/ph250/roth1/" target="_blank">Graham Roth: Bluetooth Wireless Technology&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Radio waves:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=TfYCnOvNnFU" target="_blank">YouTube: Traveling Waves: Crash Course Physics #17&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=qV4lR9EWGlY" target="_blank">YouTube: Sound: Crash Course Physics #18&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=IRBfpBPELmE" target="_blank">YouTube: Light Is Waves: Crash Course Physics #39&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=sRX2EY5Ubto" target="_blank">YouTube: Radio waves&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=7eutept5h0Q" target="_blank">YouTube: Electromagnetic waves and the electromagnetic spectrum | Physics | Khan Academy&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Priors all the way down</title><link>https://www.angelaambroz.com/posts/priors_all_the_way_down/</link><pubDate>Mon, 18 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/priors_all_the_way_down/</guid><description>&lt;p>Today I learned something very handy: how to encode subjective beliefs into a Bayesian prior when you only have information on the quantiles.&lt;/p>
&lt;p>I hadn&amp;rsquo;t realized it, but this is &lt;em>super&lt;/em> useful: nobody can give you a fully described distribution, but everyone can give you a range of likelihoods, and talking with people is one (important) way to inform your prior. For example, a person might say, &amp;ldquo;well, I&amp;rsquo;m pretty sure most people love pizza between 50 and 70 happiness points&amp;rdquo;, or somesuch. Previously, I wouldn&amp;rsquo;t have known what to do with that information. How do I fit a probability density function around that pizza love? When I have only two vague points?&lt;/p>
&lt;p>In the past, whenever I wanted to set a prior, I would do one of the following:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Set an &lt;strong>uninformative one&lt;/strong>, such as the &lt;a href="http://mathworld.wolfram.com/UniformDistribution.html" target="_blank">uniform distribution&lt;/a>. This assumes that everyone loves pizza an equal amount.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Set a prior based on some historical data, e.g. fitting a &lt;a href="https://en.wikipedia.org/wiki/Beta_distribution" target="_blank">beta distribution&lt;/a> to some observed historical data and pray that nothing has changed since that data was collected/it doesn&amp;rsquo;t bias my updating too hard. I feel like this is Sullied Bayes, though, since we&amp;rsquo;re not technically supposed to be using data in the &amp;ldquo;setting the prior&amp;rdquo; stage. But, well, okay, I&amp;rsquo;ve done it. I do it.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Build a model in &lt;a href="https://github.com/pymc-devs/pymc3" target="_blank">PyMC3&lt;/a>, hand-picking some distributions and hand-picking their parameters, based on some subjective and vague understanding of the world. E.g. &amp;ldquo;I know that I love an average pizza at about 70 points and I guess I&amp;rsquo;ll use a Normal distribution around that mean with a low variance of, uh, 5 points, because - honestly - pizza is never &lt;em>that&lt;/em> bad, right?&amp;rdquo; What nonsense, I know.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>But today I was hanging out on &lt;a href="https://stats.stackexchange.com/" target="_blank">StatsOverflow&lt;/a> and came across a very useful idea: how to incorporate quantiles information into a prior. YES. What a useful thing.&lt;/p>
&lt;p>Here&amp;rsquo;s how it works in practice:&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>SCENE 1. The RENAISSANCE BOTTEGA where you work. &lt;a href="https://en.wikipedia.org/wiki/Florence_Cathedral" target="_blank">Brunelleschi&amp;rsquo;s DUOMO&lt;/a> can be seen via a semi-open window. Enter your COLLEAGUE, stage left, &lt;a href="http://www.shakespeare-online.com/plays/winter_3_3.html" target="_blank">pursued by a bear&lt;/a>. Upon closer glance, you see that the bear is not a bear, but instead a shimmering &lt;strong>beta distribution&lt;/strong> of indeterminate shape and size. YOU are enchanted.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOU: I am enchanted! Tell me more about your &lt;strong>beta distribution&lt;/strong>! What is it about?&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOUR COLLEAGUE: This beta distribution refers to the pizza example from previous paragraphs ago! I know not much yet, but my priors are that most people like pizza between 50 and 70 happiness points! Where 100 is maximum happiness!&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOU (meditatively): What in the world do you mean by &amp;ldquo;most people&amp;rdquo;&amp;hellip;?&lt;/p>
&lt;/blockquote>
&lt;p>In this case, I would: (a) assume &amp;ldquo;most people&amp;rdquo; means &amp;ldquo;95% of people&amp;rdquo;, (b) normalize my pizza happiness points down to a beta distribution-able scale (&lt;code>50 - 70&lt;/code> becoming &lt;code>0.5 - 0.7&lt;/code>), and, (c) numerically calculate, using a least squares errors-ish approach and &lt;a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fmin.html" target="_blank">scipy&amp;rsquo;s optimization algorithms&lt;/a>, the beta parameters, $\alpha$ and $\beta$, that yield the correct proportions along a beta&amp;rsquo;s cumulative distribution function. That is, find the $\alpha$ and $\beta$ where &lt;code>Pr(X &amp;lt; 0.5) = 0.025&lt;/code> and &lt;code>Pr(X &amp;lt; 0.7) = 0.975&lt;/code>. You can read more about the method &lt;a href="https://stats.stackexchange.com/a/58792/46721" target="_blank">here&lt;/a> and solving it using scipy&amp;rsquo;s &lt;code>optimize.fmin&lt;/code> algorithm &lt;a href="https://www.codeproject.com/Articles/56371/Finding-Probability-Distribution-Parameters-from-P" target="_blank">here&lt;/a>. I did such a thing, and voila!&lt;/p>
&lt;p>And now we can do descriptive stats of this crazy ol&amp;rsquo; prior we just confabulated out of the air!&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>SCENE 2. The BOTTEGA at night. You are manually debugging a NEURAL NETWORK using a power tool that emits sparks. A 3D PRINTER is printing Brunelleschi&amp;rsquo;s DOME onto plastic.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOUR COLLEAGUE (entering suddenly): Do you have it?! Do you have the numbers!&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOU: I do. (raising paper triumphantly) Our prior belief about the average, by the power of the&lt;/p>
&lt;/blockquote>
&lt;p>$$E(X) = \frac{\alpha}{\alpha+\beta}$$&lt;/p>
&lt;blockquote>
&lt;p>incantation, is that it&amp;rsquo;s approximately 0.602137284331 -&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOUR COLLEAGUE: Hermahgerrddd STAHP. Don&amp;rsquo;t use droning floating point precision to imply accuracy! It doesn&amp;rsquo;t even matter, too. Since we&amp;rsquo;ll be updating that with actual data soon, it&amp;rsquo;ll become irrelevant.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOU: So true. Long live the posterior!&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>YOUR COLLEAGUE: Long may it reign.&lt;/p>
&lt;/blockquote>
&lt;h2 class="relative group">Reading
&lt;div id="reading" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#reading" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://stats.stackexchange.com/questions/58564/help-me-understand-bayesian-prior-and-posterior-distributions" target="_blank">Stats StackExchange: Help me understand Bayesian prior and posterior distributions&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://stats.stackexchange.com/questions/235711/do-two-quantiles-of-a-beta-distribution-determine-its-parameters" target="_blank">Stats StackExchange: Do two quantiles of a beta distribution determine its parameters?&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.johndcook.com/blog/2010/01/31/parameters-from-percentiles/" target="_blank">John Cook: Parameters and percentiles&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.codeproject.com/Articles/56371/Finding-Probability-Distribution-Parameters-from-P" target="_blank">John Cook: Finding Probability Distribution Parameters from Percentiles&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://aphyr.com/posts/341-hexing-the-technical-interview" target="_blank">Hexing the technical interview&lt;/a> - related to this post in style, not content; v wonderful&lt;/li>
&lt;/ul></description></item><item><title>How I read</title><link>https://www.angelaambroz.com/posts/how_i_read/</link><pubDate>Sun, 17 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/how_i_read/</guid><description>&lt;p>This year, I &lt;a href="https://www.goodreads.com/user_challenges/7069901" target="_blank">read 104 books&lt;/a>. My goal was 100. This is probably the maximum number of books I can read and still get something out of. The last year I read 100+ books was &lt;a href="https://www.goodreads.com/user_challenges/1149366" target="_blank">2014&lt;/a>, and that was - oh man - a &lt;em>very&lt;/em> good year for reading. I discovered some treasures like &lt;a href="https://www.goodreads.com/review/show/877308964?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Jonathan Strange &amp;amp; Mr Norrell&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/899838430?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Asterios Polyp&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/1088729609?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Spam&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/1041147648?book_show_action=false&amp;amp;from_review_page=1" target="_blank">The Everything Store&lt;/a>, &lt;a href="https://www.goodreads.com/review/show/934825707?book_show_action=false&amp;amp;from_review_page=1" target="_blank">the first set of Michael Palin&amp;rsquo;s diaries&lt;/a>, and forgotten sf classic &lt;a href="https://www.goodreads.com/review/show/1060724983?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Floating Worlds&lt;/a>. Hooo man, such book nostalgia. What a year. This year has been - meh, pretty good. Fine. Whatever.&lt;/p>
&lt;p>Anyway, people sometimes ask me how I read so &amp;ldquo;fast&amp;rdquo;. I don&amp;rsquo;t think I read very quickly: it&amp;rsquo;s more like a marathon, using many different vehicles, than a sprint. But I love reading, and I love talking books, so here are my current reading habits:&lt;/p>
&lt;h2 class="relative group">1. Audiobooks
&lt;div id="1-audiobooks" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#1-audiobooks" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This year, 60+ of the books I read were audiobooks. I discovered audiobooks in 2016 when I had a super long commute (1.5 hours daily) and, following the dramatic and emotionally wringing Election 2016, I needed a break from podcasts. Rather than staring into space or awkwardly avoiding eye contact with other commuters (SO AWKWARD), I decided to start climbing my mythical book mountain - a mountain I had been building since the late 90s. Could it be summited?! Audiobooks made the dream&amp;hellip; well, a possibility.&lt;/p>
&lt;p>Also! Around the time I started audio-reading, a friend of mine said two things which further changed my reading life:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>&amp;ldquo;You should &amp;lsquo;speed&amp;rsquo; listen.&amp;rdquo;&lt;/strong> Yes! My attention actually wanders &lt;em>less&lt;/em> if I speed audio up to &lt;code>1.5x&lt;/code> or &lt;code>1.75x&lt;/code>. I think audiobook narrators read intentionally quite slowly (and enunciate really well!), so &lt;code>1.5x - 1.75x&lt;/code> is just a bit faster than normal speech. This can get a bit weird for highly produced audiobooks or radio plays, where there&amp;rsquo;s music and sound effects, but meh - it&amp;rsquo;s not a huge deal. At these speeds, I can get through a standard ~300 page book in 2-3 days, usually.&lt;/li>
&lt;li>&lt;strong>&amp;ldquo;There&amp;rsquo;s no such thing as chore time anymore, there&amp;rsquo;s just podcast time.&amp;rdquo;&lt;/strong> I don&amp;rsquo;t love tidying, but I love a tidy space, and I realized that I could &lt;em>crush&lt;/em> all my daily TODOs if I was jamming to &lt;a href="https://www.goodreads.com/review/show/1928921222?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Tversky and Kahneman&amp;rsquo;s bickering&lt;/a> or &lt;a href="https://www.goodreads.com/review/show/2169069208?book_show_action=false&amp;amp;from_review_page=1" target="_blank">sobbing uncontrollably over Eleanor and Park&amp;rsquo;s teen romance&lt;/a>. Hell yeah, laundry time! Does that tub need a scrubbing?! LET&amp;rsquo;S DO THIS.&lt;/li>
&lt;/ol>
&lt;p>Also, exercise is another notable chunk of time when I get my audio-reading jam on.&lt;/p>
&lt;p>Buying &lt;strong>wireless headphones&lt;/strong> made things even easier - now I could cook to &lt;a href="https://www.goodreads.com/review/show/1830819667?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Trevor Noah&lt;/a>, jog to &lt;a href="https://www.goodreads.com/review/show/2150033129?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Ursula K. LeGuin&lt;/a>, and deadlift to &lt;a href="https://www.goodreads.com/review/show/2138432370?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Kim Stanley Robinson&lt;/a>. Glorious!&lt;/p>
&lt;h2 class="relative group">2. Technical books
&lt;div id="2-technical-books" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#2-technical-books" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>My mythical book mountain now has a considerable second peak devoted to computer science and machine learning. Enter&amp;hellip; &lt;a href="https://www.oreilly.com/" target="_blank">O&amp;rsquo;Reilly&lt;/a>. And &lt;a href="https://www.manning.com/" target="_blank">Manning&lt;/a>. And &lt;a href="https://www.nostarch.com/" target="_blank">No Starch&lt;/a>. I read these at work, mostly.&lt;/p>
&lt;h2 class="relative group">3. Graphic novels
&lt;div id="3-graphic-novels" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#3-graphic-novels" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Graphic novels are &lt;em>great&lt;/em> - gorgeous art, witty writing, some really out-there storylines. I didn&amp;rsquo;t start reading graphic novels until a few years ago, when a friend shoved &lt;a href="https://www.goodreads.com/review/show/188331012?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Y: The Last Man&lt;/a> into my hands (well, external hard drive) and, lo! A great love was born.&lt;/p>
&lt;h2 class="relative group">4. Digital sabbaths
&lt;div id="4-digital-sabbaths" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#4-digital-sabbaths" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Digital sabbathing merits its own post, but the basic idea is: no screens of any kind for 24 hours. After some debate, this includes Kindles. I have a pile of dead-tree books that also need a-readin&amp;rsquo;, and digital sabbaths are often the only times I actually get to them.&lt;/p>
&lt;h2 class="relative group">5. Always be reading
&lt;div id="5-always-be-reading" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#5-always-be-reading" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>As I said, it&amp;rsquo;s a marathon, not a sprint. I always have at least one book in circulation and I&amp;rsquo;m always (audio-)reading. My favorite feeling is those brief moments being in between books - &amp;ldquo;OH BOY WHAT SHALL I READ NEXT&amp;rdquo; - and I love curating and re-ordering my various wish lists.&lt;/p>
&lt;h2 class="relative group">6. Cut the chord
&lt;div id="6-cut-the-chord" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#6-cut-the-chord" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Another thing that I would recommend is getting ruthless about DNFing (did not finish-ing). Life&amp;rsquo;s too short to plow through terrible/boring books, and languishing in that &amp;ldquo;must finish boring book&amp;rdquo; limbo is never worth it.&lt;/p>
&lt;h2 class="relative group">7. I already bought these books with my taxes
&lt;div id="7-i-already-bought-these-books-with-my-taxes" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#7-i-already-bought-these-books-with-my-taxes" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>It was this year, 2017, that I discovered that: ho my God, you can borrow audiobooks and ebooks from your local library! So magical! I use the &lt;a href="https://meet.libbyapp.com/" target="_blank">Libby app&lt;/a> now and max out my holds.&lt;/p>
&lt;h2 class="relative group">8. Social motivation, i.e. Goodreads, i.e. ego (let&amp;rsquo;s be real)
&lt;div id="8-social-motivation-ie-goodreads-ie-ego-lets-be-real" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#8-social-motivation-ie-goodreads-ie-ego-lets-be-real" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Most book clubs I&amp;rsquo;ve gone to have been wine-and-snacks clubs, really, but Goodreads! Ah! How that website has motivated me. I love seeing what my friends are reading. I love showing off what I&amp;rsquo;m reading. I &lt;em>love&lt;/em> writing my reviews and I love reading my friend&amp;rsquo;s reviews. Hell, I love reading &lt;em>my&lt;/em> old reviews. It&amp;rsquo;s like a diary, with books! It&amp;rsquo;s like a book club that never ends! It&amp;rsquo;s inspiring, and fun, and the ego-boost of seeing my friends &lt;code>like&lt;/code> one of my reviews, or seeing myself inch closer to my annual reading goal, is big. BIG. I think that&amp;rsquo;s also the reason I can&amp;rsquo;t get many of my friends to do Goodreads: the most common complaint is, &amp;ldquo;Oh, I don&amp;rsquo;t read enough.&amp;rdquo; I always tell them not to think of it as a race, but - well - I guess there is a performance aspect to it? I dunno. I just love writing reviews.&lt;/p>
&lt;h2 class="relative group">9. Insatiable/ravenous curiosity
&lt;div id="9-insatiableravenous-curiosity" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#9-insatiableravenous-curiosity" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I often overestimate books and expect most of them to change my life. A few do! A FEW DO. The human brain releases the most dopamine (and gets addicted quickest) when rewards are randomly dispensed, so there you go: this book &lt;em>may&lt;/em> change your life. Who knows! Pull the lever!&lt;/p></description></item><item><title>Power bummer</title><link>https://www.angelaambroz.com/posts/power_bummer/</link><pubDate>Thu, 14 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/power_bummer/</guid><description>&lt;p>I&amp;rsquo;ve been thinking a lot about power lately. One of my favorite things! I needed to calculate power for some experiments we wanted to run at work and, as with all things, I was seized by existential doubt.&lt;/p>
&lt;p>As a brief intro: &lt;strong>statistical power&lt;/strong> is the likelihood of seeing an effect size when there is one. For those of you that like &lt;a href="https://en.wikipedia.org/wiki/Type_I_and_type_II_errors" target="_blank">Type I/II errors&lt;/a>, your power is your ability to minimize your Type II errors (false negatives). I think it might be fun to do a power walk-through (or power-walk through, heh), but I&amp;rsquo;ll leave that for another day. For now, assuming you like stats and you like power, here are some thoughts on some stuff I&amp;rsquo;ve been reading.&lt;/p>
&lt;h2 class="relative group">Why we normally use power
&lt;div id="why-we-normally-use-power" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#why-we-normally-use-power" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Say you want to measure the effect of something. For example, what&amp;rsquo;s the &lt;a href="https://www.aeaweb.org/articles?id=10.1257/app.1.1.112" target="_blank">effect of textbooks on student learning&lt;/a> (not much)? What&amp;rsquo;s the effect of nearby job opportunities on &lt;a href="https://academic.oup.com/qje/article-abstract/127/2/753/1823744?redirectedFrom=fulltext" target="_blank">parents&amp;rsquo; investment in their daughters&amp;rsquo; education&lt;/a> (big)? What&amp;rsquo;s the effect of Facebook on workers&amp;rsquo; productivity? Or of protein on a person&amp;rsquo;s likelihood to commit a crime? Or whatever. I&amp;rsquo;m just making things up. There&amp;rsquo;s lots of possible experiments out there.&lt;/p>
&lt;p>To detect an effect size, you can go about things as a &lt;strong>frequentist&lt;/strong> or as a &lt;strong>Bayesian&lt;/strong>. We&amp;rsquo;ll stick with the former for now, since that&amp;rsquo;s what most people do. But a Bayes post - many Bayes posts - will come! I love Bayes. Anyway, under the frequentist worldview, you are faced with this reality:&lt;/p>
&lt;ul>
&lt;li>You can pull a sample from a population.&lt;/li>
&lt;li>If you pull a large sample, you&amp;rsquo;ll probably be more likely to hit the population average. (See the &lt;a href="https://en.wikipedia.org/wiki/Law_of_large_numbers" target="_blank">law of large numbers&lt;/a>.)&lt;/li>
&lt;li>But you could be unlucky and have pulled a crappy sample, whose average is way off the map.&lt;/li>
&lt;li>Anyway, you&amp;rsquo;ll be working on a bell curve, which is convenient for the statistical tests you&amp;rsquo;ll run. (See the &lt;a href="https://en.wikipedia.org/wiki/Law_of_large_numbers" target="_blank">central limit theorem&lt;/a>.)&lt;/li>
&lt;li>In an experiment, you &lt;em>think&lt;/em> you&amp;rsquo;re pulling from two populations - your control population, and your treatment population. A population which has been unalterably changed by your experiment!&lt;/li>
&lt;/ul>
&lt;p>The first thing people usually ask is: so how big should our sample be? This is where power comes in. Power is the likelihood of detecting an effect when there is one (i.e. when there &lt;em>is&lt;/em> a separate population you&amp;rsquo;re sampling from, i.e. when things &lt;em>did&lt;/em> change). It looks like this:&lt;/p>
&lt;p>It&amp;rsquo;s that red thing. The &amp;ldquo;industry standard&amp;rdquo; is power = 80%, so you solve your sample size for that. &lt;em>How&lt;/em> you solve it depends on what you think the shape of those distributions are. For now, following the &lt;a href="https://en.wikipedia.org/wiki/Statistical_power#Example" target="_blank">Wikipedia example walk-through&lt;/a>, let&amp;rsquo;s assume we&amp;rsquo;re going to run a t-test of significance between two independently-pulled sample means, and we&amp;rsquo;ll shoot for a 5% statistical significance level. In that case, the math would be:&lt;/p>
&lt;p>where&lt;/p>
&lt;ul>
&lt;li>$B(1)$ is power&lt;/li>
&lt;li>$\phi$ is the quantile function&lt;/li>
&lt;li>$1.64$ is the t-value threshold for significance&lt;/li>
&lt;li>$n$ is your sample size&lt;/li>
&lt;li>$\hat{\sigma_{D}}$ is the standard error&lt;/li>
&lt;/ul>
&lt;p>Normally, you fix $B = 0.8$ (for 80% power) and solve for $n$. There&amp;rsquo;s lots of online calculators and built-it methods in &lt;code>R&lt;/code> (&lt;a href="http://stat.ethz.ch/R-manual/R-patched/library/stats/html/power.prop.test.html" target="_blank">&lt;code>power.prop.test&lt;/code>&lt;/a>), &lt;code>Stata&lt;/code> (&lt;a href="https://www.stata.com/features/power-and-sample-size/" target="_blank">&lt;code>power&lt;/code>&lt;/a>), and, for Python, the &lt;code>statsmodels.power&lt;/code> module in &lt;code>statsmodels&lt;/code> (&lt;a href="http://www.statsmodels.org/dev/stats.html?highlight=power#module-statsmodels.stats.power" target="_blank">docs&lt;/a>).&lt;/p>
&lt;p>Here&amp;rsquo;s power for a simple A/B test:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">power_calc&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">minimum_detectable_effect&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">A_mean&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;column_of_interest&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">mean&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">B_mean&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">A_mean&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">minimum_detectable_effect&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stat_sig_threshold&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.95&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">desired_power&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.8&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Detecting any changes of &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">A_mean&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> -&amp;gt; &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">B_mean&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> and above.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std_effect_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">B_mean&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">A_mean&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;column_of_interest&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n_per_group&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sms&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">TTestIndPower&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">solve_power&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std_effect_size&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">power&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">desired_power&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">alpha&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">stat_sig_threshold&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">ratio&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">n_per_group&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This returns the sample size per experimental arm (&lt;code>n_per_group&lt;/code>). If you were running an A/B test, then you&amp;rsquo;d need to multiply that by 2 to get your total sample size needed. Generally, you maximize power by splitting cohorts up evenly, though you don&amp;rsquo;t necessarily &lt;em>have&lt;/em> to.&lt;/p>
&lt;h2 class="relative group">Why power can fail us
&lt;div id="why-power-can-fail-us" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#why-power-can-fail-us" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I read a super interesting blog from the Airbnb engineering team: &lt;a href="https://medium.com/airbnb-engineering/selection-bias-in-online-experimentation-c3d67795cceb" target="_blank">Selection Bias in Online Experimentation: A Method for Winner’s Curse in A/B Testing&lt;/a>. The tldr on it is that we tend to compound upward biases when aggregating cumulative effects over sequential experiments. In other words: don&amp;rsquo;t add up wrong numbers! Or you&amp;rsquo;ll get a very wrong number!&lt;/p>
&lt;p>The blog went into some heavy stats/prob math, but my general intuition was: when we calculate power and hunt for significance, we often privilege large effect sizes. Note above that the &lt;em>minimum&lt;/em> detectable effect size is just that: a minimum. If we were to observe a huge value in the &lt;code>B&lt;/code> cohort, for example, the LLN/CLT would tell us that such an effect would be highly improbably random. In other words, it&amp;rsquo;s probably an effect! What we then do (which is wrong) is take that point estimate as &lt;em>the&lt;/em> effect size. In other words: big estimated effects are more likely to look statistically significant (and therefore &amp;ldquo;win&amp;rdquo;) but may not actually be that big. The true effect might be there, just smaller. But we write down the big number. This is the &amp;ldquo;winner&amp;rsquo;s curse&amp;rdquo;: we favor big effects, since they satisfy our need for significance, and we miss small effects since they look insignificant.&lt;/p>
&lt;p>Wonderful statistician/contrarian &lt;a href="http://andrewgelman.com/" target="_blank">Andrew Gelman&lt;/a> has a recent paper about this as well: &lt;a href="http://www.stat.columbia.edu/~gelman/research/published/weisburd_28.05.2017.pdf" target="_blank">Type M error might explain Weisburd’s Paradox&lt;/a> (co-authors are Torbjørn Skardhamar and Mikko Aaltonen). He makes a convincing case that our quest for statistical significance and power calculations (especially ex post power calcs) - driven by a publication bias that favors positive, significant results - doom us to bias our effect size upwards. In the aggregate, as John Ioannidis would say, &lt;a href="http://journals.plos.org/plosmedicine/article?id=10.1371/journal.pmed.0020124" target="_blank">most research findings are false&lt;/a>. But we can&amp;rsquo;t even be sure, because most people don&amp;rsquo;t even publish their data at all! Thus making meta studies even harder to do!&lt;/p>
&lt;ul>
&lt;li>Figure 1 from &lt;a href="http://www.stat.columbia.edu/~gelman/research/published/weisburd_28.05.2017.pdf" target="_blank">Gelman et al. 2017&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Some other take-aways from Gelman&amp;rsquo;s paper:&lt;/p>
&lt;ul>
&lt;li>They propose ditching the Type I/II error methodology/obsession, since it doesn&amp;rsquo;t apply to studies that have non-deterministic, heterogenous outcomes (i.e. basically every study of human behavior). Instead, they discuss a new focus on &lt;strong>Type S&lt;/strong> (sign) and &lt;strong>Type M&lt;/strong> (magnitude) errors - i.e. minimizing getting things qualitatively and exaggeratedly wrong. The above figure is, I guess, how you&amp;rsquo;d go about determining those likelihoods.&lt;/li>
&lt;li>There is a thing called the &amp;ldquo;Weisburd paradox&amp;rdquo;, which is that sample sizes have not actually been shown to improve power. (A &lt;a href="https://link.springer.com/article/10.1007/s11292-014-9212-9" target="_blank">replication study&lt;/a>.)&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Conclusion
&lt;div id="conclusion" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>The conclusion I always get from this stuff is that it&amp;rsquo;s all &lt;a href="https://en.wikipedia.org/wiki/Lies,_damned_lies,_and_statistics" target="_blank">lies, damned lies, and statistics&lt;/a>! In other words, I&amp;rsquo;ll do power out of interest and maybe even to build intuition, but - if I can - I&amp;rsquo;ll trust something Bayesian instead.&lt;/p>
&lt;h2 class="relative group">Reading
&lt;div id="reading" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#reading" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://www.stat.columbia.edu/~gelman/research/published/weisburd_28.05.2017.pdf" target="_blank">Gelman et al. 2017&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://medium.com/airbnb-engineering/selection-bias-in-online-experimentation-c3d67795cceb" target="_blank">Airbnb engineering: Selection Bias in Online Experimentation
A Method for Winner’s Curse in A/B Testing&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=GPYzY9I78CI" target="_blank">Talks at Google: John Ioannidis - &amp;ldquo;Reproducible Research: True or False?&amp;rdquo;&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://datacolada.org/" target="_blank">The Data Colada blog&lt;/a> (for general fun)&lt;/li>
&lt;/ul></description></item><item><title>Automatic desktop backgrounds</title><link>https://www.angelaambroz.com/posts/automatic_desktop_backgrounds/</link><pubDate>Tue, 12 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/automatic_desktop_backgrounds/</guid><description>&lt;p>One of my first Python projects was automating a daily desktop background. I think it&amp;rsquo;s a good project for beginners since it&amp;rsquo;s fun (new desktop delight!), it&amp;rsquo;s a good exercise in breaking down a vague idea (desktop delight?) into manageable chunks (one of the biggest wisdoms in programming!), and you can learn about a bunch of different useful things: interacting with the web and APIs, interacting with files, and scheduling jobs on your computer.&lt;/p>
&lt;h2 class="relative group">Tutorial assumptions
&lt;div id="tutorial-assumptions" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#tutorial-assumptions" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>You have some version of Python installed on your computer.&lt;/li>
&lt;li>You know how to run a Python script from the command line.&lt;/li>
&lt;li>You have a text editor (e.g. &lt;code>Sublime&lt;/code>) that you like.&lt;/li>
&lt;/ul>
&lt;p>My setup is: I&amp;rsquo;m using a &lt;a href="https://github.com/pyenv/pyenv-virtualenv" target="_blank">pyenv virtual environment&lt;/a> on OSX with Python 3.6.0 installed. I also would recommend installing &lt;code>ipython&lt;/code>, since it provides such a nice shell.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install ipython
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 class="relative group">Break it down
&lt;div id="break-it-down" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#break-it-down" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>One of the biggest wisdoms of programming is that it teaches you to break large tasks down into manageable parts. As I&amp;rsquo;ve gotten more experienced, I&amp;rsquo;ve noticed that this process happens faster: I can break things down more quickly, and I can hold more complex pieces in my head. In the beginning, though, it was more of a challenge - yet it was always very useful - to break down a project into a bunch of sub-tasks, and tackle each sub-task &lt;a href="https://www.goodreads.com/book/show/12543.Bird_by_Bird" target="_blank">bird by bird&lt;/a>. Don&amp;rsquo;t be afraid to make those sub-tasks very, &lt;em>very&lt;/em> sub (e.g. &amp;ldquo;Figure out how to turn on Python&amp;rdquo;).&lt;/p>
&lt;p>Here, our main objective is &lt;strong>write a Python script that automatically changes our desktop background to something cool every morning&lt;/strong>. We can break this down into the following steps:&lt;/p>
&lt;ol>
&lt;li>Find a place that has lots of cool pictures.&lt;/li>
&lt;li>Grab pics.&lt;/li>
&lt;li>Set pic as desktop background.&lt;/li>
&lt;li>Have this happen on a regular schedule.&lt;/li>
&lt;/ol>
&lt;p>Here&amp;rsquo;s what you learn at each step:&lt;/p>
&lt;ol>
&lt;li>Well, not much, but browsing pics is fun.&lt;/li>
&lt;li>How to interact with APIs.&lt;/li>
&lt;li>How to interact with your OS.&lt;/li>
&lt;li>How to schedule stuff on your computer.&lt;/li>
&lt;/ol>
&lt;h2 class="relative group">Step 0: Setup
&lt;div id="step-0-setup" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-0-setup" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>For a small script like this, I would probably have my Favorite Text Editor open, in addition to a shell window with &lt;code>ipython&lt;/code>&amp;rsquo;s shell running. On my machine, this might mean I&amp;rsquo;ll use the &lt;code>ipython&lt;/code> shell to test stuff out, and build the script out in &lt;code>Sublime&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">me@machine $ ipython
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Python 3.6.1 &lt;span class="o">(&lt;/span>default, Jul &lt;span class="m">10&lt;/span> 2017, 14:13:01&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Type &lt;span class="s1">&amp;#39;copyright&amp;#39;&lt;/span>, &lt;span class="s1">&amp;#39;credits&amp;#39;&lt;/span> or &lt;span class="s1">&amp;#39;license&amp;#39;&lt;/span> &lt;span class="k">for&lt;/span> more information
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">IPython 6.1.0 -- An enhanced Interactive Python. Type &lt;span class="s1">&amp;#39;?&amp;#39;&lt;/span> &lt;span class="k">for&lt;/span> help.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">In &lt;span class="o">[&lt;/span>1&lt;span class="o">]&lt;/span>:
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;h2 class="relative group">Step 1: Find a place that has cool pics
&lt;div id="step-1-find-a-place-that-has-cool-pics" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-1-find-a-place-that-has-cool-pics" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>&lt;a href="https://apod.nasa.gov/apod/astropix.html" target="_blank">NASA&amp;rsquo;s Astronomy pic of the day&lt;/a>, I choose you!&lt;/p>
&lt;p>Other good options:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.theatlantic.com/photo/" target="_blank">Photo @ The Atlantic&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.reddit.com/r/ColorizedHistory/" target="_blank">r/ColorizedHistory&lt;/a>&lt;/li>
&lt;li>other subreddits?&lt;/li>
&lt;/ul>
&lt;p>One thing that might inform where you grab your daily picture from is: does this place have an API? Or will I be scraping?&lt;/p>
&lt;blockquote>
&lt;p>When grabbing stuff from the web, you usually have two choices: an API, or scraping. An API - or &lt;a href="https://en.wikipedia.org/wiki/Application_programming_interface" target="_blank">application programming interface&lt;/a> - is generally preferable, in that the web developers have already prepared an endpoint for programmatic interactions: e.g. for Python scripts pinging it every day for a picture! Web scraping, where you ping the front end of the website, is not ideal - since you&amp;rsquo;re trawling through HTML and hoping that the HTML tags don&amp;rsquo;t change.&lt;/p>
&lt;/blockquote>
&lt;p>Of the above options, &lt;a href="https://en.wikipedia.org/wiki/Application_programming_interface" target="_blank">Reddit&lt;/a> and &lt;a href="https://api.nasa.gov/api.html#apod" target="_blank">NASA&amp;rsquo;s APOD&lt;/a> have APIs, but I can&amp;rsquo;t seem to find one for The Atlantic. This might tip the balance in favor of Reddit or NASA - interacting with APIs is usually way easier.&lt;/p>
&lt;h2 class="relative group">Step 2: Grab pics
&lt;div id="step-2-grab-pics" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#step-2-grab-pics" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>EASIER SAID THAN DONE, you may say. Never fear. Let&amp;rsquo;s break this down even further:&lt;/p>
&lt;ul>
&lt;li>2.1. Find the API endpoint for grabbing pictures.&lt;/li>
&lt;li>2.2. Use Python to ping said endpoint.&lt;/li>
&lt;li>2.3. Save the returned image file somewhere.&lt;/li>
&lt;/ul>
&lt;p>NASA&amp;rsquo;s API documentation is &lt;a href="https://api.nasa.gov/api.html#apod" target="_blank">here&lt;/a>. The endpoint we&amp;rsquo;ll be hitting is &lt;code>https://api.nasa.gov/planetary/apod?api_key=YOURKEY&lt;/code> where you&amp;rsquo;ll need to register with NASA and have them give you an API key. (This lets API developers track the number of pings you hit their API with - they want to ensure people don&amp;rsquo;t completely kill their servers by pinging a lot. Usually these &amp;ldquo;rate limits&amp;rdquo; are pretty high - thousands per day or whatever. Not something we have to worry about when writing a simple personal script - but definitely something that comes up for industrial strength API work.)&lt;/p>
&lt;p>Anyway, here&amp;rsquo;s what gets returned by the NASA APOD API when you hit their endpoint with the example key:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;date&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2017-12-12&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;explanation&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;What&amp;#39;s up in the sky this winter? The featured graphic gives a few highlights for Earth&amp;#39;s northern hemisphere. Viewed as a clock face centered at the bottom, early winter sky events fan out toward the left, while late winter events are projected toward the right. Objects relatively close to Earth are illustrated, in general, as nearer to the cartoon figure with the telescope at the bottom center -- although almost everything pictured can be seen without a telescope. Highlights of this winter&amp;#39;s sky include the Geminids meteor shower peaking this week, the constellation of Orion becoming notable in the evening sky, and many planets being visible before sunrise in February. As true in every season, the International Space Station (ISS) can be sometimes be found drifting across your sky if you know just when and where to look.&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;hdurl&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://apod.nasa.gov/apod/image/1712/Winter1718Highlights_Universe2go_4994.jpg&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;media_type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;image&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;service_version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;v1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;title&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Highlights of the Winter Sky&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://apod.nasa.gov/apod/image/1712/Winter1718Highlights_Universe2go_960.jpg&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ah, beloved &lt;a href="https://www.json.org/" target="_blank">JSON&lt;/a>, lingua franca of the programmatic internet! Hello!&lt;/p>
&lt;p>What&amp;rsquo;s nice about the JSON data format is that, since it&amp;rsquo;s structured in &lt;code>key: value&lt;/code> pairs, you can access the value you want if you know the key. Here, we want to download a cool space picture - looks like we can find one at the &lt;code>url&lt;/code> key.&lt;/p>
&lt;p>To the Python! I like the &lt;a href="http://docs.python-requests.org/en/master/" target="_blank">&lt;code>requests&lt;/code>&lt;/a> library for its wonderful, readable documentation, and its wonderful, readable levels of abstraction. Interacting with APIs is molto painless with &lt;code>requests&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;url&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will print out our desired &lt;code>.jpg&lt;/code>. To actually download that &lt;code>.jpg&lt;/code>, we can use the Python standard library&amp;rsquo;s &lt;code>urllib.request&lt;/code> module.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">urllib.request&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">date&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Create a string variable that prettifies today&amp;#39;s date&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">today&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">today&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;%Y%B&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">todays_file&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">_nasa_apod.jpg&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">today&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Grab the image URL from the earlier API request&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">image_url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;url&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Download said file into current working directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">urllib&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">urlretrieve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">image_url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">todays_file&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I&amp;rsquo;m doing a few things above. Beyond just downloading the file (&lt;code>urllib.request.urlretrieve&lt;/code>), I&amp;rsquo;m also formatting the filename such that it&amp;rsquo;ll have today&amp;rsquo;s date in there (for a handy reference on string formatting, I recommend &lt;a href="http://strftime.org/" target="_blank">http://strftime.org/&lt;/a>).&lt;/p>
&lt;h2 class="relative group">3. Set pic as desktop background
&lt;div id="3-set-pic-as-desktop-background" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#3-set-pic-as-desktop-background" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This is the bit that depends on your OS - and, honestly, this is the bit that I &lt;em>still&lt;/em> have no idea what it&amp;rsquo;s doing. I just found this code somewhere on the intertoobs and plugged it in:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">AppKit&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">NSWorkspace&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">NSScreen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ws&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">NSWorkspace&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sharedWorkspace&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">NSURL&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">fileURLWithPath_&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">todays_file&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">screen&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">NSScreen&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">screens&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">error&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setDesktopImageURL_forScreen_options_error_&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">screen&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{},&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This uses Apple&amp;rsquo;s &lt;a href="https://developer.apple.com/documentation/appkit" target="_blank">AppKit&lt;/a> Python library to set the image on the currently active desktop. I&amp;rsquo;ve tried fiddling with the arguments in &lt;code>setDesktopImageURL_forScreen_options_error_&lt;/code> to have it, for example, scale and resize images appropriately, and apply the image to &lt;em>all&lt;/em> desktops, not just the active one. But no luck - and, okay, not much will either. It works 90% of the time, and I&amp;rsquo;m happy with that!&lt;/p>
&lt;h2 class="relative group">4. Have this happen on a regular schedule
&lt;div id="4-have-this-happen-on-a-regular-schedule" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#4-have-this-happen-on-a-regular-schedule" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>You can schedule things to run on your machine using &lt;code>cron&lt;/code>, a &lt;a href="https://en.wikipedia.org/wiki/Cron" target="_blank">job scheduler for Unix&lt;/a>. One key thing about &lt;code>cron&lt;/code> is that scheduled jobs won&amp;rsquo;t run if your computer is asleep - so schedule it to happen when your computer is always likely to be awake (e.g. during work hours). Otherwise, on a Mac, you can use &lt;a href="http://www.launchd.info/" target="_blank">launchd&lt;/a> to have a background daemon run your script - even when your computer is sleeping. I haven&amp;rsquo;t bothered with this.&lt;/p>
&lt;p>To have &lt;code>cron&lt;/code> run your script, I found &lt;a href="http://www.techradar.com/how-to/computing/apple/terminal-101-creating-cron-jobs-1305651" target="_blank">this tutorial&lt;/a> super helpful. You basically need to edit your &lt;code>crontab&lt;/code> by adding a line like the following:&lt;/p>
&lt;pre tabindex="0">&lt;code>30 7 * * * /path/to/cool/script/cool_script.py
&lt;/code>&lt;/pre>&lt;p>The above says: run &lt;code>cool_script.py&lt;/code> every morning at 7:30AM (your computer&amp;rsquo;s time zone). You can check to see if any cron jobs are currently scheduled on your machine by running &lt;code>crontab -l&lt;/code> in Terminal.&lt;/p>
&lt;h2 class="relative group">Voila!
&lt;div id="voila" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#voila" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I don&amp;rsquo;t actually use NASA&amp;rsquo;s APOD for my own script. Instead, I have a list of image-heavy subreddits that I randomly select from. I&amp;rsquo;ve had this script running for ~3 years (!) now, and it has given me about 70% delight, 25% meh, and 5% embarrassment (be careful what you automatically download!). Here are some recent desktops that were really top-notch:&lt;/p>
&lt;p>&lt;em>&lt;a href="https://www.artstation.com/artwork/L3gbw" target="_blank">Kasai, by Joseph Biwald&lt;/a> found via &lt;a href="https://www.reddit.com/r/ImaginaryLandscapes/comments/3i19pu/kasai_by_joseph_biwald_oc/" target="_blank">r/ImaginaryLandscapes&lt;/a>&lt;/em>&lt;/p>
&lt;p>&lt;em>Aurora Borealis over Norway, by Max Rive, from NASA&amp;rsquo;s APOD, found via &lt;a href="https://www.reddit.com/r/spaceporn/comments/7is2gm/in_green_company_aurora_over_norway_2916_3579/" target="_blank">r/spaceporn&lt;/a>&lt;/em>&lt;/p>
&lt;p>&lt;em>Emerald Lake, Yoho National Park, British Columbia, found via &lt;a href="https://www.reddit.com/r/waterporn/comments/72uk5j/emerald_lake_yoho_national_park_british_columbia/" target="_blank">r/waterporn&lt;/a>&lt;/em>&lt;/p>
&lt;p>&lt;em>Star Trek- USS Enterprise NCC-1701-D cutaway- Rusted Gear Art, found via &lt;a href="https://www.reddit.com/r/StarshipPorn/comments/6v2z8s/star_trek_uss_enterprise_ncc1701d_cutaway_rusted/" target="_blank">r/StarShipPorn&lt;/a>&lt;/em>&lt;/p></description></item><item><title>Journey to the center of data science</title><link>https://www.angelaambroz.com/posts/journey_to_the_center_of_data_science/</link><pubDate>Mon, 04 Dec 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/journey_to_the_center_of_data_science/</guid><description>&lt;p>I&amp;rsquo;ve been asked by more than two people about what my &amp;ldquo;journey to the center of data science&amp;rdquo; was and, well, one of my core values is &lt;em>automation&lt;/em>. So here&amp;rsquo;s my response to those people. Next, I&amp;rsquo;ll write a bot that will just auto-reply this appropriately, heh.&lt;/p>
&lt;blockquote>
&lt;p>Usual warning/caveat: &lt;em>your mileage may vary&lt;/em>.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 class="relative group">My path
&lt;div id="my-path" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#my-path" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This is in chronological order, starting from 2014 to ~now.&lt;/p>
&lt;p>&lt;strong>Glossary&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;code>*&lt;/code> = how much each resource is still applicable to my day-to-day, where more = better&lt;/li>
&lt;li>💵 = whether I paid any money for it (as opposed to, e.g., having it reimbursed)&lt;/li>
&lt;li>🐝 = taken as part of Georgia Tech&amp;rsquo;s &lt;a href="http://www.omscs.gatech.edu/" target="_blank">OMSCS&lt;/a> program (this costs 💵 for degree credit, but is freely available on Udacity if you don&amp;rsquo;t want to take it for credit)&lt;/li>
&lt;/ul>
&lt;p>I&amp;rsquo;ve also put the approximate amount of time spent ingesting (not digesting!) the resource.&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>Background: &lt;a href="https://www.american.edu/cas/economics/" target="_blank">BS in economics and mathematics&lt;/a>, &lt;a href="https://www.ox.ac.uk/admissions/graduate/courses/mphil-economics?wssl=1" target="_blank">MPhil in economics&lt;/a> + &lt;a href="https://www.linkedin.com/in/angelaambroz/" target="_blank">several years working&lt;/a> as a research manager and economist in &lt;a href="https://www.povertyactionlab.org/" target="_blank">university research labs&lt;/a> and &lt;a href="https://www.twaweza.org/" target="_blank">non-profit sector&lt;/a>.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>💵 &lt;a href="https://www.goodreads.com/review/show/1041283796?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Interactive Data Visualization for the Web by Scott Murray&lt;/a> &lt;code>*&lt;/code> (~1 month)&lt;/li>
&lt;li>&lt;a href="https://www.udacity.com/course/data-visualization-and-d3js--ud507" target="_blank">Udacity - Data Visualization and D3.js&lt;/a> &lt;code>*&lt;/code> (~3-4 weeks)&lt;/li>
&lt;li>&lt;a href="https://www.udacity.com/course/programming-foundations-with-python--ud036" target="_blank">Udacity - Programming Foundations with Python&lt;/a> &lt;code>***&lt;/code> (~2 weeks + several months &lt;a href="https://github.com/angelaambroz/year-second" target="_blank">working on first project&lt;/a>)&lt;/li>
&lt;li>&lt;a href="https://www.udacity.com/course/how-to-use-git-and-github--ud775" target="_blank">Udacity - How to Use Git and GitHub&lt;/a> &lt;code>***&lt;/code> (on and off, maybe 2 weeks)&lt;/li>
&lt;li>&lt;a href="https://www.coursera.org/learn/ml-foundations" target="_blank">Coursera - Machine Learning Foundations: A Case Study Approach&lt;/a> &lt;code>**&lt;/code> (~4 weeks)&lt;/li>
&lt;li>&lt;a href="http://www.railsbridge.org/" target="_blank">RailsBridge&lt;/a> &lt;code>*&lt;/code> (1 weekend)&lt;/li>
&lt;li>&lt;a href="https://iacs.seas.harvard.edu/computefest-2016" target="_blank">ComputeFest 2016&lt;/a> &lt;code>**&lt;/code> (2 days)&lt;/li>
&lt;li>💵 &lt;a href="http://www.cs171.org/2017/index.html" target="_blank">Harvard Extension School - CS171: Visualization&lt;/a> &lt;code>*&lt;/code> (~240 hours AKA 15 hours/week for a semester)&lt;/li>
&lt;li>&lt;a href="http://ballingt.com/othercomputers/" target="_blank">Boston Python User Group - Talking to other computers with Python&lt;/a> &lt;code>***&lt;/code> (1 day)&lt;/li>
&lt;li>&lt;a href="https://openvisconf.com/2016/" target="_blank">OpenVisConf 2016&lt;/a> &lt;code>***&lt;/code> (3 days)&lt;/li>
&lt;li>&lt;a href="https://www.udacity.com/course/intro-to-relational-databases--ud197" target="_blank">Udacity - Intro to Relational Databases&lt;/a> &lt;code>***&lt;/code> (~2 weeks)&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>Got first data science job&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>&lt;a href="https://www.udacity.com/course/intro-to-machine-learning--ud120" target="_blank">Udacity - Intro to Machine Learning&lt;/a> &lt;code>**&lt;/code> (~3 weeks, unfinished!)&lt;/li>
&lt;li>💵 &lt;a href="https://canvas.harvard.edu/courses/29726/" target="_blank">Harvard Extension School - CS109A: Intro to Data Science&lt;/a> &lt;code>***&lt;/code> (~320 hours AKA full semester, 20 hours/week)&lt;/li>
&lt;li>💵 &lt;a href="https://canvas.harvard.edu/courses/20101/assignments/syllabus" target="_blank">Harvard Extension School - CS109B: Advanced topics in data science&lt;/a> &lt;code>***&lt;/code> (~320 hours AKA full semester, 20 hours/week)&lt;/li>
&lt;li>&lt;a href="https://www.datacamp.com/courses/deep-learning-in-python" target="_blank">DataCamp - Deep Learning in Python&lt;/a> &lt;code>***&lt;/code> (~4 whirlwind hours, applied to CS109B final project)&lt;/li>
&lt;li>&lt;a href="https://ericmjl.github.io/data-testing-tutorial/" target="_blank">Boston Python User Group - Data testing tutorial&lt;/a> &lt;code>***&lt;/code> (1 day)&lt;/li>
&lt;li>💵 &lt;a href="https://www.goodreads.com/review/show/1920496518?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Doing Data Science by Rachel Schutt, Cathy O&amp;rsquo;Neil&lt;/a> &lt;code>**&lt;/code> (~10 hours)&lt;/li>
&lt;li>&lt;a href="https://github.com/ericmjl/Network-Analysis-Made-Simple" target="_blank">Boston Python User Group - Network analysis made simple&lt;/a> &lt;code>***&lt;/code> (1 day)&lt;/li>
&lt;li>&lt;a href="http://www.clojurebridge.org/" target="_blank">ClojureBridge&lt;/a> &lt;code>**&lt;/code> (1 day + a loooong time working on the crypto puzzle)&lt;/li>
&lt;li>&lt;a href="https://www.goodreads.com/review/show/1864250202?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Bayesian Methods for Hackers: Probabilistic Programming and Bayesian Inference by Cameron Davidson-Pilon&lt;/a> &lt;code>***&lt;/code> (~10 hours)&lt;/li>
&lt;li>💵 &lt;a href="https://www.goodreads.com/review/show/1956416919?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Mastering Regular Expressions by Jeffrey E.F. Friedl&lt;/a> &lt;code>***&lt;/code> (~10 hours)&lt;/li>
&lt;li>💵 &lt;a href="https://www.goodreads.com/review/show/2175875409?book_show_action=false&amp;amp;from_review_page=1" target="_blank">Learning the bash Shell by Cameron Newham, Bill Rosenblatt&lt;/a> &lt;code>***&lt;/code> (~10 hours)&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>Got second data science job&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>&lt;a href="http://2017.clojure-conj.org/" target="_blank">Clojure/conj 2017&lt;/a>, &lt;code>*&lt;/code> (~2 days)&lt;/li>
&lt;li>&lt;a href="https://www.edx.org/course/cs50s-introduction-computer-science-harvardx-cs50x" target="_blank">EdX - CS50: Introduction to Computer Science&lt;/a> &lt;code>***&lt;/code> (~60 hours, &lt;a href="http://angelaambroz.com/blog/posts/2018/Jan/19/cs50_lecture_1/" target="_blank">see the journey here!&lt;/a>)&lt;/li>
&lt;li>&lt;a href="https://tomtomfest.com/2018/01/31/applied-machine-learning-conference-2018/" target="_blank">TomTomFest - Applied Machine Learning Conference 2018&lt;/a>, &lt;code>**&lt;/code> (1 day)&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>&lt;a href="http://angelaambroz.com/blog/posts/2018/Apr/03/two_announcements/" target="_blank">Admitted&lt;/a> to Georgia Tech&amp;rsquo;s OMSCS&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>&lt;a href="https://www.lynda.com/SQL-tutorials/Advanced-SQL-Data-Scientists/559183-2.html" target="_blank">Lynda - Advanced SQL for Data Scientists&lt;/a> &lt;code>***&lt;/code> (~2 hours)&lt;/li>
&lt;li>🐝 &lt;a href="https://www.omscs.gatech.edu/cs-7637-knowledge-based-artificial-intelligence-cognitive-systems" target="_blank">Georgia Tech/Udacity - Knowledge-Based AI&lt;/a> &lt;code>*&lt;/code> (120 hours, AKA full semester at ~10 hours/week)&lt;/li>
&lt;li>&lt;a href="https://www.lynda.com/Web-Development-tutorials/Polyglot-Web-Development/618730-2.html" target="_blank">Lynda - Polyglot Web Development&lt;/a> &lt;code>*&lt;/code> (~2 hours)&lt;/li>
&lt;li>&lt;a href="https://pydata.org/dc2018/schedule/" target="_blank">PyData DC 2018&lt;/a> - &lt;code>***&lt;/code> (3 days)&lt;/li>
&lt;li>&lt;a href="https://www.destroyallsoftware.com/screencasts/catalog/a-compiler-from-scratch" target="_blank">Destroy All Software - A compiler from scratch&lt;/a> - &lt;code>***&lt;/code> (2 days)&lt;/li>
&lt;li>&lt;a href="https://www.lynda.com/Ruby-tutorials/essential-training/47905-2.html" target="_blank">Lynda - Ruby Essential Training&lt;/a> &lt;code>***&lt;/code> (~10 hours)&lt;/li>
&lt;li>&lt;a href="https://www.lynda.com/Git-tutorials/GIT-Intermediate-Techniques/664821-2.html" target="_blank">Lynda - Git Intermediate Techniques&lt;/a> &lt;code>**&lt;/code> (~3 hours)&lt;/li>
&lt;li>&lt;a href="https://www.lynda.com/Data-Science-tutorials/DevOps-Data-Scientists/578073-2.html" target="_blank">Lynda - DevOps for Data Scientists&lt;/a> &lt;code>*&lt;/code> (~1 hour)&lt;/li>
&lt;li>💵&lt;a href="https://www.destroyallsoftware.com/screencasts/catalog/test-runner-from-scratch" target="_blank">Destroy All Software - A test runner from scratch&lt;/a> &lt;code>***&lt;/code> (2 days)&lt;/li>
&lt;li>&lt;a href="https://www.lynda.com/Kafka-tutorials/Kafka-Essential-Training/585254-2.html" target="_blank">Lynda - Kafka Essential Training&lt;/a> &lt;code>*&lt;/code> (2 days)&lt;/li>
&lt;li>&lt;a href="https://www.lynda.com/Python-tutorials/Parallel-Concurrent-Programming-Python-1/2812129-2.html" target="_blank">Lynda - Parallel and Concurrent Programming with Python I&lt;/a> &lt;code>***&lt;/code> (2 days)&lt;/li>
&lt;li>&lt;a href="https://www.lynda.com/Flask-tutorials/Learning-Flask/704154-2.html" target="_blank">Lynda - Learning Flask&lt;/a> &lt;code>*&lt;/code> (1 day)&lt;/li>
&lt;li>&lt;a href="https://www.lynda.com/Ruby-Rails-tutorials/Ruby-Rails-5-Essential-Training/500551-2.html" target="_blank">Lynda - Ruby on Rails 5 Essential Training&lt;/a> &lt;code>***&lt;/code> (only did half of it, many hours)&lt;/li>
&lt;li>&lt;a href="https://thoughtbot.com/upcase/onramp-to-vim" target="_blank">Thoughtbot - Onramp to Vim&lt;/a> &lt;code>***&lt;/code> (~1 week)&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>&lt;strong>You can see what I&amp;rsquo;m currently doing &lt;a href="https://www.linkedin.com/in/angelaambroz/" target="_blank">on LinkedIn&lt;/a>.&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 class="relative group">General resources
&lt;div id="general-resources" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#general-resources" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Those are things I actually went through, top to bottom. In addition, here are some reference resources I use a lot (and find very helpful):&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.youtube.com/user/dataschool" target="_blank">YouTube - Data School&lt;/a>: Great for getting a handle on &lt;code>pandas&lt;/code>&amp;rsquo;s syntax.&lt;/li>
&lt;li>&lt;a href="https://chrisalbon.com/" target="_blank">Chris Albon - Data wrangling tutorials&lt;/a>: More &lt;code>pandas&lt;/code>.&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/watch?v=TjZBTDzGeGg&amp;amp;list=PLUl4u3cNGP63gFHB6xb-kVBiQHYe_4hSi" target="_blank">YouTube - MIT 6.034 Artificial Intelligence, Fall 2010&lt;/a>: Clear, precise and deep explanations of SVMs, random forests, neural nets and more. I need to go through this top to bottom.&lt;/li>
&lt;li>&lt;a href="http://www-bcf.usc.edu/~gareth/ISL/" target="_blank">An Introduction to Statistical Learning by James et al.&lt;/a>: The main textbook, with examples in R (unfortunately&amp;hellip;).&lt;/li>
&lt;li>&lt;a href="http://web.stanford.edu/~hastie/ElemStatLearn/" target="_blank">Elements of Statistical Learning by Hastie et al.&lt;/a>: More main textbook.&lt;/li>
&lt;li>&lt;a href="https://www.amazon.com/Artificial-Intelligence-3rd-Winston/dp/0201533774" target="_blank">Artificial Intelligence by Winston&lt;/a>: Winston is great.&lt;/li>
&lt;li>&lt;a href="https://www.khanacademy.org/math/linear-algebra" target="_blank">Khan Academy - Linear algebra&lt;/a>: Refreshing the fundamentals!&lt;/li>
&lt;li>&lt;a href="https://www.khanacademy.org/math/statistics-probability" target="_blank">Khan Academy - Statistics and probability&lt;/a>: More excellent fundamentals!&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/user/mathematicalmonk" target="_blank">YouTube - mathematicalmonk&lt;/a>: Very good explanations of more advanced math and probability topics - his video on Markov Chain Monte Carlo (MCMC) sampling was very helpful.&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/c/3blue1brown" target="_blank">YouTube - 3Brown1Blue&lt;/a>: Enthusiastic math.&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/user/Vihart" target="_blank">YouTube - Vihart&lt;/a>: More enthusiastic math.&lt;/li>
&lt;li>&lt;a href="https://regexr.com/" target="_blank">regexr&lt;/a>: A beautiful and well-designed site for debugging regular expressions.&lt;/li>
&lt;li>&lt;a href="https://alf.nu/RegexGolf" target="_blank">Regex Golf&lt;/a>: Think long and hard and don&amp;rsquo;t touch that keyboard.&lt;/li>
&lt;li>&lt;a href="https://apps.ankiweb.net/" target="_blank">Anki&lt;/a>: Spaced repetition flashcards app. This changed &lt;em>a lot&lt;/em> for me. I&amp;rsquo;ll post a longer blog post about it sometime, but, for now, &lt;a href="http://augmentingcognition.com/ltm.html" target="_blank">read Michael Nielsen&amp;rsquo;s post, &lt;em>Augmenting long term memory&lt;/em>&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.youtube.com/channel/UC8ENHE5xdFSwx71u3fDH5Xw" target="_blank">YouTube/ThePrimeagen&lt;/a>: Helpful Vim tutorials.&lt;/li>
&lt;li>&lt;a href="https://www.hackerrank.com/dashboard" target="_blank">Hackerrank&lt;/a>: Coding puzzles; helpfully includes SQL (which is rare-ish). The one that slows down my browser and overheats my CPU (why?!).&lt;/li>
&lt;li>&lt;a href="https://leetcode.com/" target="_blank">LeetCode&lt;/a>: More coding puzzles. I prefer the UI on this one. But it&amp;rsquo;s more algorithms + data structures-oriented. The broey one.&lt;/li>
&lt;li>&lt;a href="https://exercism.org/" target="_blank">Exercism&lt;/a>: Yet more coding puzzles. Also a nice way to learn a new language. The friendly one.&lt;/li>
&lt;/ul>
&lt;p>And, of course, Google, StackOverflow, and YouTube.&lt;/p>
&lt;hr>
&lt;h2 class="relative group">It never ends
&lt;div id="it-never-ends" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#it-never-ends" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I consider this a start, and I still have a &lt;em>lot&lt;/em> of stuff I want to learn. It&amp;rsquo;s a big topic, and the &lt;code>TOLEARN&lt;/code> list is only growing&amp;hellip;!&lt;/p></description></item><item><title>Hello, Pelican!</title><link>https://www.angelaambroz.com/posts/hello_pelican/</link><pubDate>Thu, 30 Nov 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/hello_pelican/</guid><description>&lt;p>Hello, world!&lt;/p>
&lt;p>For the past few months, I&amp;rsquo;d been looking to start a mostly-tech blog.&lt;/p>
&lt;p>I already have my &lt;a href="https://p-pcc.blogspot.com" target="_blank">dusty ol&amp;rsquo; movie review blog&lt;/a>, and I have my &lt;a href="https://www.goodreads.com/author/show/5341811.Angela_Ambroz" target="_blank">ragingly active book review sorta-blog on Goodreads&lt;/a> but I also wanted a place to document and share what I&amp;rsquo;m learning along my &lt;em>Journey to the Center of the Machine&lt;/em>. Given how much I&amp;rsquo;ve benefitted from other tech blogs - &lt;a href="http://jvns.ca/" target="_blank">Julia Evans&amp;rsquo;s&lt;/a> or &lt;a href="http://www.daiyi.co/blog/" target="_blank">daiyi&amp;rsquo;s&lt;/a> or &lt;a href="http://norvig.com/" target="_blank">Peter Norvig&lt;/a> or &lt;a href="https://nedbatchelder.com/" target="_blank">Ned Batchelder&amp;rsquo;s&lt;/a> - it also seemed like giving back to the community was a good thing and something I should do.&lt;/p>
&lt;h3 class="relative group">Desired specs
&lt;div id="desired-specs" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#desired-specs" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>In looking for a blog framework, I knew I wanted to:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Minimize front end work&lt;/strong>. I spent a lot of 2014-2015 learning front end stuff: HTML, CSS, Javascript, Bootstrap, and - most especially - &lt;a href="https://d3js.org/" target="_blank">d3.js&lt;/a>. As much as I love a good data visualization, I did &lt;em>not&lt;/em> want to fuss over all that again.&lt;/li>
&lt;li>&lt;strong>Automate as much as possible&lt;/strong>. The above, plus could I haz scripts?&lt;/li>
&lt;li>&lt;strong>Markdown support&lt;/strong>. Plz, so lazy.&lt;/li>
&lt;li>&lt;strong>Python&lt;/strong>. I once attended a one-day workshop where we built little blogs using GitHub Pages and &lt;a href="https://jekyllrb.com/" target="_blank">Jekyll&lt;/a>. Unfortunately, Jekyll&amp;rsquo;s in Ruby - but surely there was something in Python?&lt;/li>
&lt;/ul>
&lt;p>Enter Pelican.&lt;/p>
&lt;h3 class="relative group">TIL: Pelican
&lt;div id="til-pelican" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#til-pelican" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;blockquote>
&lt;p>Pelican is a static site generator, written in Python.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&amp;ndash; &lt;a href="http://docs.getpelican.com/en/stable/" target="_blank">official Pelican docs&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>Static site generators take your content, pour it into your templates and output the result as static pre-generated HTML, CSS, JS &amp;amp; image files. You can then just upload the resulting folder of output to your server and you’re done.&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;p>&amp;ndash; &lt;a href="http://duncanlock.net/blog/2013/05/17/how-i-built-this-website-using-pelican-part-1-setup/" target="_blank">How I built this website, using Pelican: Part 1 - Setup, Duncan Lock&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;p>To get started, I followed &lt;a href="http://docs.getpelican.com/en/stable/quickstart.html" target="_blank">Pelican&amp;rsquo;s quickstart&lt;/a> and, after fussing over where to put it (my directory structure is a mess, please send help) and fussing over keeping my Python environment clean (please send more help), I just said &amp;ldquo;whatevs&amp;rdquo; and pip installed it onto my base Python like a maniac:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install pelican markdown
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mkdir ~/some/file/path/pelican_hello_world
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/some/file/path/pelican_hello_world
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pelican-quickstart
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>pelican-quickstart&lt;/code> runs you through a bunch of questions on how you&amp;rsquo;d like to set up your project: for example, the title, author, and so on. (This is for convenience; you can change your answers later by editing your &lt;code>pelicanconf.py&lt;/code> file.) Once you&amp;rsquo;ve finished, you&amp;rsquo;ll have some pre-populated files and a directory structure like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pelican_hello_world/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -- content/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -- output/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -- develop_server.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -- fabfile.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -- Makefile
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -- pelicanconf.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> -- publishconf.py
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The money bits are in &lt;code>content/&lt;/code> (where you&amp;rsquo;ll draft your blog posts) and &lt;code>output/&lt;/code> (where Pelican will dump the static site, ready to be published to the internet). You can change where Pelican dumps your site - I changed the &lt;code>$OUTPUT_DIR&lt;/code> variable in the &lt;code>Makefile&lt;/code> (&lt;em>not&lt;/em> &lt;code>pelicanconf.py&lt;/code>, per this [issue](&lt;a href="https://github.com/getpelican/pelican/issues/11" target="_blank">https://github.com/getpelican/pelican/issues/11&lt;/a> 71)) to where the rest of my website is.&lt;/p>
&lt;p>You can write your blog posts in Markdown (or &lt;code>.rst&lt;/code>, &lt;code>.adoc&lt;/code>, &lt;code>.html&lt;/code>) and stick them in &lt;code>content/&lt;/code>. You can then run &lt;code>make html&lt;/code> and &lt;code>make serve&lt;/code> to launch a local server and see the changes at &lt;code>localhost:8000&lt;/code> in your browser.&lt;/p>
&lt;p>There are some &amp;ldquo;meta&amp;rdquo; fields at the top of a blog post in &lt;code>content/&lt;/code>, which Pelican&amp;rsquo;s (magical?) (CSS?) something parses to auto-populate the resulting &lt;code>.html&lt;/code> in &lt;code>output/&lt;/code>.&lt;/p>
&lt;p>At this point, I had a few things I wanted to figure out:&lt;/p>
&lt;h3 class="relative group">What does Pelican want from me? (&lt;code>metadata&lt;/code>)
&lt;div id="what-does-pelican-want-from-me-metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#what-does-pelican-want-from-me-metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>According to the &lt;a href="http://docs.getpelican.com/en/stable/content.html#file-metadata" target="_blank">docs&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">Title: My super title
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Date: 2010-12-03 10:20
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Modified: 2010-12-05 19:30
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Category: Python
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Tags: pelican, publishing
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Slug: my-super-post
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Authors: Alexis Metaireau, Conan Doyle
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Summary: Short version for index and feeds
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">This is the content of my super blog post.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Okay.&lt;/p>
&lt;h3 class="relative group">How do I make it look pretty? (&lt;code>themes&lt;/code>)
&lt;div id="how-do-i-make-it-look-pretty-themes" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-do-i-make-it-look-pretty-themes" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>There is a frankenrepo &lt;a href="https://github.com/getpelican/pelican-themes" target="_blank">over on GitHub&lt;/a> of 120+ themes. Following their instructions, you can &lt;code>git clone&lt;/code> the entire repo to your home directory, and then - in the &lt;code>pelicanconf.py&lt;/code> config file, add:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">THEME&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">/&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">to&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">pelican&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">repo&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">clone&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">some&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">theme&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">name&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I didn&amp;rsquo;t love this. First, there&amp;rsquo;s a LOT of themes. (You can browse an endless scroll of them &lt;a href="http://www.pelicanthemes.com/" target="_blank">here&lt;/a>). Second, it seemed like grabbing a gnarly giant repo - with tons of devilish &lt;code>git submodules&lt;/code> (ack) - was not a super efficient way to grab one or two themes. Third, as a Pelican noob, I wanted to make something look like my &lt;a href="https://www.angelaambroz.com" target="_blank">existing website&lt;/a> - and customizing an existing theme didn&amp;rsquo;t seem much easier than just customizing base Pelican.&lt;/p>
&lt;p>The &lt;a href="http://docs.getpelican.com/en/stable/themes.html" target="_blank">docs&lt;/a> discuss creating a theme:&lt;/p>
&lt;ul>
&lt;li>Basically, you follow a directory structure, where you have a &lt;code>static/&lt;/code> dir (of &lt;code>css/&lt;/code> and &lt;code>images/&lt;/code> and whatever other assets you want to just port across to &lt;code>output/&lt;/code>), and then a bunch of &lt;code>.html&lt;/code> templates for each of the different pages Pelican&amp;rsquo;s &lt;code>output/&lt;/code> creates.&lt;/li>
&lt;li>Ah ha! This could be where, if one wanted, one could dump their &lt;a href="https://v4-alpha.getbootstrap.com/components/navbar/" target="_blank">Bootstrap navbar&lt;/a>, stylish fonts, and soothing CSS.&lt;/li>
&lt;/ul>
&lt;p>I spent a &lt;em>lot&lt;/em> of time on this, way more than I wanted or intended. One of my specs is &amp;ldquo;minimize front end&amp;rdquo;! But, argh, it had to be done. What I ended up doing was:&lt;/p>
&lt;ol>
&lt;li>Using the &lt;code>pelican-bootstrap3&lt;/code> theme as my base.&lt;/li>
&lt;li>Rewriting a bunch of that theme&amp;rsquo;s &lt;code>style.css&lt;/code> to look like my original website.&lt;/li>
&lt;li>Doing a lot of (fun) fussing over widgets and doo-dads.&lt;/li>
&lt;/ol>
&lt;h3 class="relative group">&lt;s>Syntactic&lt;/s> Scriptastic sugar
&lt;div id="ssyntactics-scriptastic-sugar" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#ssyntactics-scriptastic-sugar" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>&lt;a href="http://nafiulis.me/making-a-static-blog-with-pelican.html" target="_blank">This blog by Nafiul Islam&lt;/a> had a pretty awesome/handy example script - &lt;code>make_entry.py&lt;/code> - which you can use to automate your posts. I fiddled with it, added &lt;code>argparse&lt;/code> and a few more options, and modified it to output &lt;code>.md&lt;/code> formatted blog templates. I&amp;rsquo;ve been using that now to auto-create drafts.&lt;/p>
&lt;p>&lt;a href="https://github.com/chrisalbon/mlai/blob/master/make_site.ipynb" target="_blank">Chris Albon also has a cool Jupyter -&amp;gt; .md -&amp;gt; Pelican workflow script&lt;/a>, though I haven&amp;rsquo;t played around with it yet. But it looks cool.&lt;/p>
&lt;h3 class="relative group">How do I integrate it with my existing website? (&lt;code>subdomains&lt;/code>)
&lt;div id="how-do-i-integrate-it-with-my-existing-website-subdomains" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#how-do-i-integrate-it-with-my-existing-website-subdomains" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;p>Subdomains are so cool. After I created the &lt;code>blog.angelaambroz.com&lt;/code> subdomain on my webhost, I thought I would just have to dump the &lt;code>output&lt;/code> contents into it, remember to link to it from the rest of the site, and - voila! Now I have a tech blog! Wooo.&lt;/p>
&lt;p>Unfortunately, tying it all together took a bit more pain and fiddling. First, there was the problem of &lt;em>relative paths&lt;/em>. I had used the &lt;code>ARTICLE_SAVE_AS&lt;/code> and &lt;code>ARTICLE_URL&lt;/code> options in my config file to auto-create year and month archives of posts (and also clean up the &lt;code>blog/&lt;/code> directory structure). Unfortunately, this messed up a bunch of things: I now had &lt;code>index.html&lt;/code> files every which way, and I was referencing up and down directory paths. It was a giant, giant pain.&lt;/p>
&lt;p>Also, the &lt;em>CSS didn&amp;rsquo;t line up&lt;/em> at first; though I think this had more to do with running a local server. But there are still some annoying disparities (e.g. the navbar on my blog has slightly dimmer font-color than the navbar on the rest of the site - argh) that, after N hours, I am too pooped to resolve. I also don&amp;rsquo;t love the idea of maintaining two distinct CSS files.&lt;/p>
&lt;h3 class="relative group">Reading list
&lt;div id="reading-list" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#reading-list" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="http://docs.getpelican.com/en/stable/" target="_blank">Official docs&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://duncanlock.net/blog/2013/05/17/how-i-built-this-website-using-pelican-part-1-setup/" target="_blank">How I built this website, using Pelican: Part 1 - Setup&lt;/a> (blog)&lt;/li>
&lt;li>&lt;a href="http://nafiulis.me/making-a-static-blog-with-pelican.html" target="_blank">Making a static blog with Pelican&lt;/a> (blog)&lt;/li>
&lt;/ul></description></item><item><title>Learning the bash Shell (2005) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/learning_the_bash_shell/</link><pubDate>Fri, 24 Nov 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/learning_the_bash_shell/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/learning_the_bash_shell/book_jacket_hu066f8129e92997e7256e457703d46d09_58115_330x0_resize_q75_box.jpg 330w,
/posts/learning_the_bash_shell/book_jacket_hu066f8129e92997e7256e457703d46d09_58115_660x0_resize_q75_box.jpg 660w,
/posts/learning_the_bash_shell/book_jacket_hu066f8129e92997e7256e457703d46d09_58115_1024x0_resize_q75_box.jpg 1024w,
/posts/learning_the_bash_shell/book_jacket_hu066f8129e92997e7256e457703d46d09_58115_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/learning_the_bash_shell/book_jacket_hu066f8129e92997e7256e457703d46d09_58115_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Cameron Newham&lt;/li>
&lt;li>Number of pages: 333&lt;/li>
&lt;li>Year published: 2005&lt;/li>
&lt;li>Year read: 2017&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Bash agility - fluency on the Unix/Linux terminal - is a super foundational meta-programming skill that I feel like gets short shrift as we all rush towards machine learning and cryptocurrency. Yo, but the stronger your bash fu, the easier your management of remote servers and such. Like, I did this the other day and basically floated away on a rainbow chariot pulled by mighty unicorns:&lt;br/>&lt;code>pip freeze &amp;gt; diff - requirements.txt&lt;/code>&lt;br/>YES, I AM POWERFUL.&lt;br/>&lt;br/>Just like &lt;a href="https://www.goodreads.com/review/show/1956416919?book_show_action=false&amp;from_review_page=1">Friedl&amp;rsquo;s book on regular expressions&lt;/a>, another clarifying book on an important meta topic, this bash book was SUPER helpful and I wish I had had it in 2014. I literally remember sitting at my desk in Dar es Salaam, staring at OSX Terminal and watching some Coursera course on some tech topic, and marveling at the instructors&amp;rsquo; bash incantations. Wtf was he doing? &lt;br/>&lt;br/>&amp;ldquo;Is there some structured way to learn about Terminal!?&amp;rdquo; I thought. I didn&amp;rsquo;t even know it was a shell language called bash! I didn&amp;rsquo;t know shell != bash! Lots of stuff. I WIIISH I had had this then.&lt;br/>&lt;br/>Anyway, yes, you can probably pick up these same bash skills by just osmosis over long periods of time. I did - there was a lot in here I had already learned (or had sorta half-known and used anyway), and I think experienced programmers will consider it real (bashy) basic. But if I had a young lady beginning her career transition journey into tech, I would hand her this and the regex book, and the keys to Udacity, and GODSPEED YOUNG MADAM. &lt;br/>&lt;br/>And now, for much meta inspiration on people&amp;rsquo;s hardware, editor, and shell choices, here&amp;rsquo;s &lt;a href="https://usesthis.com/" target="_blank">https://usesthis.com/&lt;/a>&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/299534" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Bayesian Methods for Hackers- Probabilistic Programming and Bayesian Inference (Addison-Wesley Data &amp; Analytics) (2015) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/bayesian_methods_for_hackers_probabilistic_programming_and_bayesian_inference_addisonwesley_data__analytics/</link><pubDate>Fri, 18 Aug 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/bayesian_methods_for_hackers_probabilistic_programming_and_bayesian_inference_addisonwesley_data__analytics/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/bayesian_methods_for_hackers_probabilistic_programming_and_bayesian_inference_addisonwesley_data__analytics/book_jacket_hu1fb7bb83665340161c4892f4677b410b_30471_330x0_resize_q75_box.jpg 330w,
/posts/bayesian_methods_for_hackers_probabilistic_programming_and_bayesian_inference_addisonwesley_data__analytics/book_jacket_hu1fb7bb83665340161c4892f4677b410b_30471_660x0_resize_q75_box.jpg 660w,
/posts/bayesian_methods_for_hackers_probabilistic_programming_and_bayesian_inference_addisonwesley_data__analytics/book_jacket_hu1fb7bb83665340161c4892f4677b410b_30471_1024x0_resize_q75_box.jpg 1024w,
/posts/bayesian_methods_for_hackers_probabilistic_programming_and_bayesian_inference_addisonwesley_data__analytics/book_jacket_hu1fb7bb83665340161c4892f4677b410b_30471_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/bayesian_methods_for_hackers_probabilistic_programming_and_bayesian_inference_addisonwesley_data__analytics/book_jacket_hu1fb7bb83665340161c4892f4677b410b_30471_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Cameron Davidson-Pilon&lt;/li>
&lt;li>Number of pages: 256&lt;/li>
&lt;li>Year published: 2015&lt;/li>
&lt;li>Year read: 2017&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>A fun and informative book on applied Bayesian modeling in Python.&lt;br/>&lt;br/>Assumes knowledge of Python and, honestly, I wouldn&amp;rsquo;t recommend this - alone - as an intro to Bayesian stuff. But if you combine this with Allen Downey&amp;rsquo;s &lt;a href="https://www.goodreads.com/book/show/18711042-think-bayes">Think Bayes&lt;/a> or Khan Academy&amp;rsquo;s &lt;a href="https://www.khanacademy.org/partner-content/wi-phi/wiphi-critical-thinking/wiphi-fundamentals/v/bayes-theorem">Bayes Theorem video&lt;/a> or a course (!), you would probably be able to get off the ground with a couple initial models quite quickly. &lt;br/>&lt;br/>This book is pitched towards people a bit beyond noob but not total hackers yet on both the PyMC spectrum (Python&amp;rsquo;s most popular (?) Bayesian modeling library&amp;hellip; after PySTAN?) and on the Bayesian stats spectrum. For example, the author intentionally hand-waves away Monte Carlo Markov Chain (MCMC) sampling as being much too mathy for this book&amp;rsquo;s purposes, which is&amp;hellip; meh, fine. There&amp;rsquo;s a bunch of intuition on what the MCMC sampling is doing and why we use it. (Though I would have introduced conjugate priors earlier, juxtaposing &amp;ldquo;easy&amp;rdquo; Bayesian models that can be solved analytically versus hard/annoying models that need sampling.) If you want a bit &lt;em>more&lt;/em> mathiness, I thought &lt;a href="https://www.youtube.com/watch?v=12eZWG0Z5gY">mathematicalmonk&amp;rsquo;s video was helpful&lt;/a>. &lt;br/>&lt;br/>There&amp;rsquo;s a good section on multi-armed bandit models (i.e. A/B testing when your sample sizes are super small), which was informative and kinda mind-blowing.&lt;br/>&lt;br/>The book is open source and you can read it for free (and make contributions) &lt;a href="https://github.com/CamDavidsonPilon/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers">on their GitHub repo&lt;/a>. This is very nice and forward-thinking/Star Trek TNG of them, thank God, but it also means that the later chapters are a bit sloppy. I cloned the repo a couple weeks ago and was gifted with a previously-unseen Chapter 7, which turned out to be a bunch of TODOs. Oh well. There&amp;rsquo;s also some typos, maybe a bit too much Personality (heh), and the nagging feeling that, gosh, I guess I &lt;em>could&lt;/em> edit their book for some open source software street cred - but then I thought, WHAT ME BE A GLORIFIED SECRETARY AGAIN NO THANK YOU, and lo, thus dideth the number of &lt;a href="https://www.wired.com/2017/06/diversity-open-source-even-worse-tech-overall/">women contributors to open source code remaineth at the 5%, the Devil&amp;rsquo;s percent&lt;/a>.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/22535757" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Mastering Regular Expressions (2006) - ⭐⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/mastering_regular_expressions/</link><pubDate>Thu, 03 Aug 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/mastering_regular_expressions/</guid><description>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Jeffrey E.F. Friedl&lt;/li>
&lt;li>Number of pages: 542&lt;/li>
&lt;li>Year published: 2006&lt;/li>
&lt;li>Year read: 2017&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Mwah, mwah! Thank you, Jeff Friedl, for finally - FINALLY - demystifying this most crucial of meta-programming skills: regular expressions. I had tried online tutorials, videos, even &lt;a href="https://github.com/bchartoff/regexcalibur">a retro bash game&lt;/a>, this and that. Nothing ever helped. This did. FINALLY. FINALLY!&lt;br/>&lt;br/>So I didn&amp;rsquo;t &amp;ldquo;read&amp;rdquo; the whole book, but whatever, the second half is reference material for languages I never use nor plan to use (Perl, PHP, etc.). Honestly, the first 2-3 chapters were sufficient; once he got into the guts of different regex languages, I felt like I was teleported back to 1983 Bay Area, sitting next to Steve Wozniak as he pecked at his clackety-clack keyboard and wrote the original BSD man pages. Awwww myyyannn, I just did &lt;code>man grep&lt;/code> to double-check my facts and DAMMIT the last update to the grep man page was 2010!!!! Way to kill my joke, Unix.&lt;br/>&lt;br/>Henyyyway. Highly recommended, though YMMV - people learn in diff ways. I had been daunted by regexes since the 2009 Stata days, and I just &lt;em>WISH&lt;/em> I had had this then.&lt;br/>&lt;br/>For my future reference (and yours), a muscle must be exercised, and here are some regex games:&lt;br/>- &lt;a href="https://alf.nu/RegexGolf" target="_blank">https://alf.nu/RegexGolf&lt;/a>&lt;br/>- &lt;a href="https://regexcrossword.com/" target="_blank">https://regexcrossword.com/&lt;/a>&lt;br/>- &lt;a href="https://www.hackerrank.com/dashboard" target="_blank">https://www.hackerrank.com/dashboard&lt;/a> has a bunch&lt;br/>- &lt;a href="https://github.com/bchartoff/regexcalibur" target="_blank">https://github.com/bchartoff/regexcalibur&lt;/a> (the bash game)&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/583628" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Doing Data Science- Straight Talk from the Frontline (2013) - ⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/doing_data_science_straight_talk_from_the_frontline/</link><pubDate>Thu, 11 May 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/doing_data_science_straight_talk_from_the_frontline/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/doing_data_science_straight_talk_from_the_frontline/book_jacket_hucde7fd84f8b97053152eb18482ad6c12_29557_330x0_resize_q75_box.jpg 330w,
/posts/doing_data_science_straight_talk_from_the_frontline/book_jacket_hucde7fd84f8b97053152eb18482ad6c12_29557_660x0_resize_q75_box.jpg 660w,
/posts/doing_data_science_straight_talk_from_the_frontline/book_jacket_hucde7fd84f8b97053152eb18482ad6c12_29557_1024x0_resize_q75_box.jpg 1024w,
/posts/doing_data_science_straight_talk_from_the_frontline/book_jacket_hucde7fd84f8b97053152eb18482ad6c12_29557_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/doing_data_science_straight_talk_from_the_frontline/book_jacket_hucde7fd84f8b97053152eb18482ad6c12_29557_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Cathy O&amp;rsquo;Neil, and Rachel Schutt&lt;/li>
&lt;li>Number of pages: 405&lt;/li>
&lt;li>Year published: 2013&lt;/li>
&lt;li>Year read: 2017&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Thus endeth my lunchtime reading book. I intermittently read this, over the course of many months, usually over a sandwich at lunch. For this style of reading, it holds up well: the chapters are discreet packets of data science chat. That said, I agree with other critiques of this book: if you&amp;rsquo;re an aspiring data scientist, this book is NOT sufficient to get you off the ground. It&amp;rsquo;s not a good beginner&amp;rsquo;s book. It&amp;rsquo;s maybe a good &amp;ldquo;pop data science&amp;rdquo; book, a pre-beginner&amp;rsquo;s book. It&amp;rsquo;s very light on the technical stuff, and, if anything, it&amp;rsquo;s more like an anthropological survey of the state of the field.&lt;br/>&lt;br/>Each chapter covers a technique or common challenge or strategy, describes the general jist of what&amp;rsquo;s going on, and then points you in the direction of papers, other books, or tutorials online. Early chapters have some &amp;ldquo;exercises&amp;rdquo;, though they&amp;rsquo;re more like general pointers of &amp;ldquo;oh, you could try this, I guess?&amp;rdquo; Later chapters don&amp;rsquo;t even bother. &lt;br/>&lt;br/>For an O&amp;rsquo;Reilly book, I was disappointed that the &lt;a href="https://github.com/oreillymedia/doing_data_science">GitHub repo&lt;/a> didn&amp;rsquo;t have, for example, the code examples mentioned in the book, or the exercises and toy datasets. (What? Are we supposed to manually copy down several pages of R code?!) Or even just a README.md with a bibliography (given how many shortened Google links are used as citations)? This makes it a starkly UNFRIENDLY book, which is weird since O&amp;rsquo;Reilly books (well, the good ones) can be very, very rich resources. This, instead, felt thin - and the repo is basically pointless. &lt;br/>&lt;br/>I &lt;em>will&lt;/em> say that I enjoyed the banter-y tone of the book, and some of the discussions of techniques (e.g. there was a great, intuitive explanation of Principal Component Analysis) and &amp;ldquo;real world&amp;rdquo; issues (e.g. how Kaggle competitions are basically data science in a vacuum; what it&amp;rsquo;s like to be a lady data scientist) were quite good. But, overall, yeah, this isn&amp;rsquo;t really a &amp;ldquo;good enough&amp;rdquo; data science book.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/17346997" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Weapons of Math Destruction- How Big Data Increases Inequality and Threatens Democracy (2016) - ⭐⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/weapons_of_math_destruction_how_big_data_increases_inequality_and_threatens_democracy/</link><pubDate>Thu, 26 Jan 2017 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/weapons_of_math_destruction_how_big_data_increases_inequality_and_threatens_democracy/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/weapons_of_math_destruction_how_big_data_increases_inequality_and_threatens_democracy/book_jacket_hud5175461ce9c069eeb6a9f4b628ab274_45046_330x0_resize_q75_box.jpg 330w,
/posts/weapons_of_math_destruction_how_big_data_increases_inequality_and_threatens_democracy/book_jacket_hud5175461ce9c069eeb6a9f4b628ab274_45046_660x0_resize_q75_box.jpg 660w,
/posts/weapons_of_math_destruction_how_big_data_increases_inequality_and_threatens_democracy/book_jacket_hud5175461ce9c069eeb6a9f4b628ab274_45046_1024x0_resize_q75_box.jpg 1024w,
/posts/weapons_of_math_destruction_how_big_data_increases_inequality_and_threatens_democracy/book_jacket_hud5175461ce9c069eeb6a9f4b628ab274_45046_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/weapons_of_math_destruction_how_big_data_increases_inequality_and_threatens_democracy/book_jacket_hud5175461ce9c069eeb6a9f4b628ab274_45046_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Cathy O&amp;rsquo;Neil&lt;/li>
&lt;li>Number of pages: 259&lt;/li>
&lt;li>Year published: 2016&lt;/li>
&lt;li>Year read: 2017&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Cathy O&amp;rsquo;Neil is one of my heroes; I love listening to her on &lt;a href="http://www.slate.com/articles/podcasts/slate_money.html">Slate Money&lt;/a>, and her less pop/more technical book, &lt;a href="http://shop.oreilly.com/product/0636920028529.do">Doing Data Science&lt;/a>, occupies a prominent place on my desk at work - and a special place in my heart. Going beyond the usual data science manuals of what a random forest is, or how to account for large, sparse data, O&amp;rsquo;Neil and her coauthor - in that book - make an almost anthropological survey of the data science &amp;ldquo;field&amp;rdquo;/profession/whatever. It&amp;rsquo;s enlightening, and it&amp;rsquo;s very real; less a textbook, more a professional guide.&lt;br/>&lt;br/>So if Doing Data Science is the &amp;ldquo;how to do your job&amp;rdquo; manual, and Slate Money is the occasional soapbox, Weapons of Math Destruction is the manifesto. With clarity, conviction and intelligence, Cathy O&amp;rsquo;Neil scalpels away at the utopian, misty-eyed tech worship that has contributed to the data science/big data bubble. She identifies the ways in which algorithms encode and perpetuate existing prejudices, and are hidden from plain sight by the obscuring (both intentional and not) use of Fancy Math.&lt;br/>&lt;br/>She notes how anti-human &amp;ldquo;market efficiency&amp;rdquo; is, and how it&amp;rsquo;s often been short-hand for unjust and unequal systems, and big data is just scaling those dumb systems way, way up. For example, the use of social network data to &amp;ldquo;enrich&amp;rdquo; lending platforms; or recidivism models that ask about where a former convict grew up, whether his/her friends are in jail, how many encounters with the police he/she has had. These algorithms - because they chase correlations to make predictions (rather than identifying causal factors) - create big-data-driven poverty traps. They are also beyond the purview of the government (and, given the new administration, will probably be for quite some time): just like your FICO score is ONLY about how often you pay your credit card bills, and NOT your demographic group, so too should these algorithms be scrutinized and regulated.&lt;br/>&lt;br/>Increasingly, O&amp;rsquo;Neil notes, the &amp;ldquo;human touch&amp;rdquo; comes at a price; in upper income groups, you get more real, live service - hearing about a job through connections, informational interviews with alumni, blah - while lower income groups are serviced by increasingly mechanized, machine learning code. The hiring and HR practices of CVS, McDonald&amp;rsquo;s, and other low wage places were especially striking (and severe): mindless, well-meaning algorithms deployed to effectively punish workers whose BMIs (itself a stupid measure of health) are too high, or who seem &amp;ldquo;anti-social&amp;rdquo; according to a creepy questionnaire, or whatever. &lt;br/>&lt;br/>I think my favorite chapter - and, of course, the most relevant one - was about the toxic brew that can be politics and data science. It was especially powerful to think through the way that, as opposed to the past, where we had &amp;ldquo;agreed upon facts&amp;rdquo; given by carpet bombing-style hegemonic culture (e.g. four news channels that everyone watched), now we have hyper-tailored DARE I SAY &amp;ldquo;alternative facts&amp;rdquo; where, by the power of marketers (who prey on confirmation bias), your neighbor&amp;rsquo;s political beliefs are the result of a very specific and private relationship between them, their web browser cookies, and some political marketer. This means you may have NO IDEA why your swingy neighbor in swingy state X thinks Candidate Y is running an underground child sex ring literally under the ground of a DC pizza shop. O&amp;rsquo;Neil (and this book was written Before The Madness) notes that these sorts of micro-targeted ads that follow you around the web are very smartly tailored; the marketers know who would be repulsed by such a stupid conspiracy theory, and who would be intrigued. And that&amp;rsquo;s just terrifying. &lt;br/>&lt;br/>Anywayyyyy. From a data perspective, my (cold dead) economist heart reminds me that OF COURSE we&amp;rsquo;re going to scale up injustice when we mindlessly maximize profit, instead of humans. We need to go back to our roots: to the philosophy and debates of Jeremy Bentham, and welfare economics, and what &amp;ldquo;utility&amp;rdquo; really means. Efficiency is not the end all, be all, despite what our current economic system seems to diktat. O&amp;rsquo;Neil also makes a good point about the repeated erroneous conflating of correlation and causation; something even the fanciest of linear algebra stochastic process meddlers fall prey to. That&amp;rsquo;s something that I see a LOT in data science: the field is built on the premise of perfect prediction - and prediction doesn&amp;rsquo;t need causation, it just needs correlation. &lt;br/>&lt;br/>OK, I will step off my soapbox. Highly recommended.&lt;br/>&lt;br/>&lt;b>edited to add&lt;/b>: OMG and I just read her delightful &lt;a href="https://mathbabe.org/2017/01/03/2017-resolutions-switch-this-shit-up/">2017 resolutions post&lt;/a>, and had much LOLs. Cathy O&amp;rsquo;Neil, you da best.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/28186015" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Think Stats (2011) -</title><link>https://www.angelaambroz.com/posts/think_stats/</link><pubDate>Wed, 04 May 2016 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/think_stats/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/think_stats/book_jacket_hu9af9ea70336186969f27d32a6f3d5544_11270_330x0_resize_q75_box.jpg 330w,
/posts/think_stats/book_jacket_hu9af9ea70336186969f27d32a6f3d5544_11270_660x0_resize_q75_box.jpg 660w,
/posts/think_stats/book_jacket_hu9af9ea70336186969f27d32a6f3d5544_11270_1024x0_resize_q75_box.jpg 1024w,
/posts/think_stats/book_jacket_hu9af9ea70336186969f27d32a6f3d5544_11270_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/think_stats/book_jacket_hu9af9ea70336186969f27d32a6f3d5544_11270_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Allen B. Downey&lt;/li>
&lt;li>Number of pages: 136&lt;/li>
&lt;li>Year published: 2011&lt;/li>
&lt;li>Year read: 2016&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>It&amp;rsquo;s a textbook. A good one. I didn&amp;rsquo;t finish it. Wiping the slate clean! I saw Allen Downey give a talk on Bayesian stats, and it was fun and informative. I think he&amp;rsquo;s great.&lt;br/>&lt;br/>One annoyance. I think I&amp;rsquo;m maybe the perfect audience for this book: someone who took stats long ago, has worked with data ever since in some capacity, but has moved further and further away from the first principles/fundamentals. Someone who speaks Python and wants to port all of her Stata skillz onto pandas (the Python library, not the Chinese bear - okay, also the Chinese bear*). So, in a way, this book was perfect for that. MY ONE COMPLAINT is that Allen provides many helper functions and .py files pre-written for you to play around with. I would have preferred less hand-holding, and more: Now build a function that will give you the cumulative distribution function! &lt;br/>&lt;br/>But then: who am I to complain. I didn&amp;rsquo;t finish it (for now). And it can be hard, sometimes, to find the perfect puzzle piece for your current skillset/desires/time constraint on the Great Learning Journey that is life.&lt;br/>&lt;br/>* images of pandas feverishly computing z-scores, while I cackle above them, &amp;ldquo;Work harder!!! Why are you so slow!!!&amp;rdquo; images of furry paws clutching pens and notebooks, scribbling&lt;br/>&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/12042357" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>How to Think Like a Computer Scientist- Learning With Python (2002) - ⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/how_to_think_like_a_computer_scientist_learning_with_python/</link><pubDate>Mon, 20 Apr 2015 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/how_to_think_like_a_computer_scientist_learning_with_python/</guid><description>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Allen B. Downey, and Jeffrey Elkner, Chris Meyers&lt;/li>
&lt;li>Number of pages: 288&lt;/li>
&lt;li>Year published: 2002&lt;/li>
&lt;li>Year read: 2015&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>First few chapters, I was like, &amp;ldquo;Duh, self-evident.&amp;quot;&lt;br/>Next few chapters, I was like, &amp;ldquo;Ooh.&amp;quot;&lt;br/>Last few chapters, I was like, &amp;ldquo;&amp;hellip;What?&amp;quot;&lt;br/>&lt;br/>Yeah, so Python is great. Flexible, durable, like Wolverine&amp;rsquo;s adamantium claws. Can it do anything? Perhaps yes. Maybe we can replace our eco-system with Python and just be done with it. &lt;br/>&lt;br/>Highly recommended, especially as a companion piece to Udacity&amp;rsquo;s (wonderful) &lt;a href="https://www.udacity.com/course/programming-foundations-with-python--ud036">Intro to Python Programming&lt;/a> course, which was bite-sized, basic, and clarified a lot of that Class stuff. (Which was sometimes mysterious in the book.) &lt;br/>&lt;br/>I second the request for more (more more) exercises, more code examples, more hands-on stuff. It gets a bit too heady otherwise.&lt;br/>&lt;br/>&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/598508" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>The Visual Display of Quantitative Information, 2nd Ed. (2001) - ⭐⭐</title><link>https://www.angelaambroz.com/posts/the_visual_display_of_quantitative_information_2nd_ed/</link><pubDate>Sun, 22 Feb 2015 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/the_visual_display_of_quantitative_information_2nd_ed/</guid><description>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Edward R. Tufte&lt;/li>
&lt;li>Number of pages: 197&lt;/li>
&lt;li>Year published: 2001&lt;/li>
&lt;li>Year read: 2015&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>It feels sacrilege to say this, but not only did I find this Classic Text of Data Visualization a complete bore, but I also disagreed with a lot of Tufte&amp;rsquo;s principles! Uh oh. Is no one going to let me near a data visualization again? Hope not. But seriously. I&amp;rsquo;m surprised this remains the go-to graphic design book for social scientists, data scientist people, etc. It feels completely outdated, not only because it&amp;rsquo;s more 1970s than a pair of huge Dan Aykroyd sideburns, but also because it&amp;rsquo;s all about static, dead-on-the-page graphics - and we live in a world where we can make our infographics animated and interactive! &lt;br/>&lt;br/>Yes, I agree that the Microsoft Office Hegemony is a bad thing - especially the way PowerPoints and Excel homogenize and bleed the passion from our work - but I just could&amp;rsquo;t agree with some of Tufte&amp;rsquo;s other principles.&lt;br/>&lt;br/>&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/17744" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Spam- A Shadow History of the Internet (Infrastructures) (2013) - ⭐⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/spam_a_shadow_history_of_the_internet_infrastructures/</link><pubDate>Mon, 27 Oct 2014 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/spam_a_shadow_history_of_the_internet_infrastructures/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/spam_a_shadow_history_of_the_internet_infrastructures/book_jacket_hud86679f39425591dbf297a6bfb7cc1ca_20157_330x0_resize_q75_box.jpg 330w,
/posts/spam_a_shadow_history_of_the_internet_infrastructures/book_jacket_hud86679f39425591dbf297a6bfb7cc1ca_20157_660x0_resize_q75_box.jpg 660w,
/posts/spam_a_shadow_history_of_the_internet_infrastructures/book_jacket_hud86679f39425591dbf297a6bfb7cc1ca_20157_1024x0_resize_q75_box.jpg 1024w,
/posts/spam_a_shadow_history_of_the_internet_infrastructures/book_jacket_hud86679f39425591dbf297a6bfb7cc1ca_20157_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/spam_a_shadow_history_of_the_internet_infrastructures/book_jacket_hud86679f39425591dbf297a6bfb7cc1ca_20157_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Finn Brunton&lt;/li>
&lt;li>Number of pages: 270&lt;/li>
&lt;li>Year published: 2013&lt;/li>
&lt;li>Year read: 2014&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Aaah. Superbly brilliant. Maybe the best book I&amp;rsquo;ve read this year? SO GOOD.&lt;br/>&lt;br/>This was basically like a five-hour &lt;a href="https://www.youtube.com/user/pbsideachannel">Idea Channel&lt;/a> episode, what with the charismatic host (Finn Brunton&amp;rsquo;s writing - so clever! so fun!), the combination of technology/futurism/literary criticism/culture theory/sociology, the awesomely interesting asides and mind-blowing anecdotes. This was one of those books that my brain absorbed like a giant sea sponge dumped into crack-filled water; I was just so thrilled, so stimulated, SO INTO IT, all the time.&lt;br/>&lt;br/>Briefly: it covers the parallel development of the spam and non-spam Internets. Like yin and yang, you kinda realize that one can&amp;rsquo;t exist without the other: what with spam being the gummy, &lt;a href="https://en.wikipedia.org/wiki/Grey_goo">gray gooey&lt;/a>, reptilian brain, capitalist slush that inevitably fills the tubes (ALL OUR TUBES, not just the Internet), pushing the edges of our global network&amp;rsquo;s technical capacities and acceptable social behaviors. It runs from the earliest proto-spams of ARPANET to the really creepy blurred-lines spam of clickbaity nonsense like, well, any post-AOL-acquisition Huffington Post article(hoo boy, did they jump the shark there, eh). &lt;br/>&lt;br/>The book was amazing because it charted, basically, my experience of the Internet, structuring and contextualizing that experience. Yo, I been online since 1995 (twenty long years, people), and I distinctly remember each spam phase: the proto-spams of AOL, the weird litspam of the mid-2000s, and now the Orwellian awfulness of Upworthy et al. and the linkbaitification of journalism. So, it was like, I FEEL THIS. And, I HAD NO IDEA.&lt;br/>&lt;br/>Another great thing about this book is that it&amp;rsquo;s a bit of an action-packed cyberpunk rollercoaster, better than the &lt;a href="https://www.goodreads.com/book/show/22328.Neuromancer">best Gibson&lt;/a> because, well, it&amp;rsquo;s real. &lt;br/>&lt;br/>Highly highly recommended. Eleventy stars.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/16718273" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Learn to Code HTML and CSS- Develop and Style Websites (2014) - ⭐⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/learn_to_code_html_and_css_develop_and_style_websites/</link><pubDate>Thu, 16 Oct 2014 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/learn_to_code_html_and_css_develop_and_style_websites/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/learn_to_code_html_and_css_develop_and_style_websites/book_jacket_hu21a6f5dc47245cd994ecc0267a21e48c_44918_330x0_resize_q75_box.jpg 330w,
/posts/learn_to_code_html_and_css_develop_and_style_websites/book_jacket_hu21a6f5dc47245cd994ecc0267a21e48c_44918_660x0_resize_q75_box.jpg 660w,
/posts/learn_to_code_html_and_css_develop_and_style_websites/book_jacket_hu21a6f5dc47245cd994ecc0267a21e48c_44918_1024x0_resize_q75_box.jpg 1024w,
/posts/learn_to_code_html_and_css_develop_and_style_websites/book_jacket_hu21a6f5dc47245cd994ecc0267a21e48c_44918_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/learn_to_code_html_and_css_develop_and_style_websites/book_jacket_hu21a6f5dc47245cd994ecc0267a21e48c_44918_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Shay Howe&lt;/li>
&lt;li>Number of pages: 306&lt;/li>
&lt;li>Year published: 2014&lt;/li>
&lt;li>Year read: 2014&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>This is a review for the &lt;a href="http://learn.shayhowe.com/html-css/">online tutorials&lt;/a> on which this book is based. It&amp;rsquo;s unclear to me how different the book is from the online tutorials, but the latter are GREAT. Extremely thorough, clear, and helpful - with tons of great resources elsewhere. I&amp;rsquo;ve bookmarked this for future use, since it really is incredibly helpful and I&amp;rsquo;ll probably want to refer back to some of the lessons as I move forward. It&amp;rsquo;s really exciting to see the sample website come alive - especially once we add our first CSS stuff! &lt;em>happy sigh&lt;/em>&lt;br/>&lt;br/>&lt;b>Edited to add&lt;/b>: Props also to the &lt;a href="http://bocoup.com/education/online/learning-sites/">Bocoup people&lt;/a>, from whom I found my way - via &lt;a href="http://learnlayout.com/">recommendations within recommendations&lt;/a> - to this resource.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/22389806" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Getting Started with D3- Creating Data-Driven Documents (2012) - ⭐⭐</title><link>https://www.angelaambroz.com/posts/getting_started_with_d3_creating_datadriven_documents/</link><pubDate>Wed, 17 Sep 2014 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/getting_started_with_d3_creating_datadriven_documents/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/getting_started_with_d3_creating_datadriven_documents/book_jacket_hu16f296174827667c07c947ffa3fdd05f_10350_330x0_resize_q75_box.jpg 330w,
/posts/getting_started_with_d3_creating_datadriven_documents/book_jacket_hu16f296174827667c07c947ffa3fdd05f_10350_660x0_resize_q75_box.jpg 660w,
/posts/getting_started_with_d3_creating_datadriven_documents/book_jacket_hu16f296174827667c07c947ffa3fdd05f_10350_1024x0_resize_q75_box.jpg 1024w,
/posts/getting_started_with_d3_creating_datadriven_documents/book_jacket_hu16f296174827667c07c947ffa3fdd05f_10350_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/getting_started_with_d3_creating_datadriven_documents/book_jacket_hu16f296174827667c07c947ffa3fdd05f_10350_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Mike Dewar&lt;/li>
&lt;li>Number of pages: 66&lt;/li>
&lt;li>Year published: 2012&lt;/li>
&lt;li>Year read: 2014&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>I&amp;rsquo;m not sure who this book is pitched to - maybe it resonates with people who already have a pretty good knowledge of JavaScript. For complete newbies, or people at level 1.1 noob, it feels really scattered and mostly baffling. I found &lt;a href="https://www.goodreads.com/review/show/1041283796?book_show_action=false">Interactive Data Visualization for the Web&lt;/a> a lot friendlier - and richer, in terms of both explanations and resources for further study. &lt;br/>&lt;br/>One (pretty big) plus point, to Mike Dewar&amp;rsquo;s credit, is his hands-on example using the New York City subway. I sometimes complain about the examples used in code tutorials (they skew heavily towards the interests of middle-aged white dudes - e.g. program a poker game! replicate Pong!), and I appreciated something that was: (1) civics-ish, (2) urban design-y, and (3) with a lot of depth (there are so many questions one could ask about the New York City subway, amirite?).&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/14514297" target="_blank">Goodreads&lt;/a>&lt;/p></description></item><item><title>Interactive Data Visualization for the Web- An Introduction to Designing with D3 (2013) - ⭐⭐⭐⭐⭐</title><link>https://www.angelaambroz.com/posts/interactive_data_visualization_for_the_web_an_introduction_to_designing_with_d3/</link><pubDate>Sun, 07 Sep 2014 00:00:00 +0000</pubDate><guid>https://www.angelaambroz.com/posts/interactive_data_visualization_for_the_web_an_introduction_to_designing_with_d3/</guid><description>&lt;p>
&lt;figure>
&lt;img
class="my-0 rounded-md"
loading="lazy"
srcset="
/posts/interactive_data_visualization_for_the_web_an_introduction_to_designing_with_d3/book_jacket_hufda8cc7a1a30b98d5833d1e38b0a581c_27632_330x0_resize_q75_box.jpg 330w,
/posts/interactive_data_visualization_for_the_web_an_introduction_to_designing_with_d3/book_jacket_hufda8cc7a1a30b98d5833d1e38b0a581c_27632_660x0_resize_q75_box.jpg 660w,
/posts/interactive_data_visualization_for_the_web_an_introduction_to_designing_with_d3/book_jacket_hufda8cc7a1a30b98d5833d1e38b0a581c_27632_1024x0_resize_q75_box.jpg 1024w,
/posts/interactive_data_visualization_for_the_web_an_introduction_to_designing_with_d3/book_jacket_hufda8cc7a1a30b98d5833d1e38b0a581c_27632_1320x0_resize_q75_box.jpg 2x"
src="https://www.angelaambroz.com/posts/interactive_data_visualization_for_the_web_an_introduction_to_designing_with_d3/book_jacket_hufda8cc7a1a30b98d5833d1e38b0a581c_27632_660x0_resize_q75_box.jpg"
alt="Book cover"
/>
&lt;/figure>
&lt;/p>
&lt;h2 class="relative group">Metadata
&lt;div id="metadata" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#metadata" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;ul>
&lt;li>Author(s): Scott Murray&lt;/li>
&lt;li>Number of pages: 270&lt;/li>
&lt;li>Year published: 2013&lt;/li>
&lt;li>Year read: 2014&lt;/li>
&lt;/ul>
&lt;h2 class="relative group">Review
&lt;div id="review" class="anchor">&lt;/div>
&lt;span
class="absolute top-0 w-6 transition-opacity opacity-0 ltr:-left-6 rtl:-right-6 not-prose group-hover:opacity-100">
&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700"
style="text-decoration-line: none !important;" href="#review" aria-label="Anchor">#&lt;/a>
&lt;/span>
&lt;/h2>
&lt;p>Awesome. Basically an intro, from the ground up, to d3.js - the powerful JavaScript library built by Mike Bostock for data visualization. I&amp;rsquo;ve been meaning to get good at d3 for a looong time. I now feel like it&amp;rsquo;s somewhat possible. Great overview of the fundamentals, lots of calming encouragement, and - thanks to its links all over the place - an amazing resource. &lt;br/>&lt;br/>FYI this book is an expansion and enrichment of Scott Murray&amp;rsquo;s freely available &lt;a href="http://alignedleft.com/tutorials/d3">d3 tutorials on his website&lt;/a>. I&amp;rsquo;d say the tutorials form the skeleton of about 50% of the book. Still worth it, though, as (1) I need this shit offline, and (2) the final chapters are pretty mind-blowing (GeoJSON, where have you been all my life?), and (3) the walk-throughs of the existing stuff are more thorough.&lt;br/>&lt;br/>On on on.&lt;/p>
&lt;p>📚 &lt;a href="https://www.goodreads.com/book/show/16087610" target="_blank">Goodreads&lt;/a>&lt;/p></description></item></channel></rss>