<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Hazel Duvall&apos;s Blog</title><description>this is a site yes</description><link>https://www.hazelduvall.dev/blog.html</link><language>en-us</language><item><title>This Is Why My Latest iOS CI Check Failed</title><link>https://www.hazelduvall.dev/blog/posts/2026-01-21-apple-intelligence.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2026-01-21-apple-intelligence.html</guid><description>Just a silly little video demonstration</description><pubDate>Wed, 21 Jan 2026 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Video courtesy of my coworker. This is running inside the iOS simulator:&lt;/p&gt;

  
  

&lt;p&gt;Yeah ok sure whatever.&lt;/p&gt;

  Video description in case it doesn&apos;t load:
  A blue circle fades into view at the top, indicating a tap on a
  chosen element. Right as the tap is about to occur, however, a system
  notification reading &quot;Ready for Apple Intelligence? Time to experience the
  new personal intelligence system.&quot; swoops in from the top, intercepting the
  tap. This takes the simulator away from the app being tested into settings,
  causing the test to fail.
</content:encoded><category>daily thoughts</category></item><item><title>Click-To-Open In Neovim With Kitty</title><link>https://www.hazelduvall.dev/blog/posts/2025-11-14-click-to-open-in-neovim-with-kitty.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2025-11-14-click-to-open-in-neovim-with-kitty.html</guid><description>An overly detailed explanation of how I copied a very basic feature from VSCode into my bespoke terminal setup</description><pubDate>Fri, 14 Nov 2025 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, I saw my coworker using VSCode, and they had this amazing feature where they could:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run ripgrep in the command pane&lt;/li&gt;
&lt;li&gt;Click on a filename it outputted&lt;/li&gt;
&lt;li&gt;To immediately open it in a new tab in the editor pane&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This, to me, was magical. However, I thought it out-of-reach for a lowly terminal user like myself, until I saw what &lt;a href=&quot;https://jyn.dev/how-i-use-my-terminal/&quot;&gt;jyn was able to do with their terminal&lt;/a&gt;. This inspired me to create my own customized setup, which I shall now explain in excruciating detail.&lt;/p&gt;
&lt;h2&gt;The Basics&lt;/h2&gt;
&lt;h3&gt;The Shell&lt;/h3&gt;
&lt;p&gt;In order to actually have anything clickable, we’ll first need to set up our command line tools to output &lt;a href=&quot;https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda&quot;&gt;Terminal Hyperlinks&lt;/a&gt; that point to the full path of the filename displayed. The tools I uses for this are &lt;a href=&quot;https://github.com/BurntSushi/ripgrep&quot;&gt;&lt;code&gt;rg&lt;/code&gt;&lt;/a&gt; (searching by file contents), &lt;a href=&quot;https://github.com/sharkdp/fd&quot;&gt;&lt;code&gt;fd&lt;/code&gt;&lt;/a&gt; (searching by filename), &amp;amp; &lt;a href=&quot;https://eza.rocks/&quot;&gt;&lt;code&gt;eza&lt;/code&gt;&lt;/a&gt; (listing directories).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# ~/.zshrc&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; rg&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;command rg --hyperlink-format=default&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; fd&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;command fd --hyperlink=auto&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# TODO: use --hyperlink=auto once eza supports it&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; ls&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;-t&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    command&lt;/span&gt;&lt;span&gt; eza&lt;/span&gt;&lt;span&gt; --hyperlink&lt;/span&gt;&lt;span&gt; &quot;&lt;/span&gt;&lt;span&gt;$@&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  else&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    command&lt;/span&gt;&lt;span&gt; eza&lt;/span&gt;&lt;span&gt; &quot;&lt;/span&gt;&lt;span&gt;$@&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because Terminal Hyperlinks are just extra text that’s interpreted + hidden by the terminal (similar to how terminal colors work), we need to be careful that this extra text is only written to the terminal, not to any pipes (&lt;code&gt;|&lt;/code&gt;) or file redirection (&lt;code&gt;&amp;gt;&lt;/code&gt;). Fortunately, most programs supporting colors/hyperlinks already have ways to detect if they’re writing to the terminal or not. Unfortunately, “most” is not “all”, and for some reason &lt;code&gt;eza&lt;/code&gt; still only has an unconditional &lt;code&gt;--hyperlink&lt;/code&gt; flag despite &lt;a href=&quot;https://github.com/eza-community/eza/pull/1059&quot;&gt;a PR about it being open for some time&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-eza&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, so we need to detect this manually. Overall not too hard to do tho. Next!!&lt;/p&gt;
&lt;h3&gt;The Terminal&lt;/h3&gt;
&lt;p&gt;I’ve been using &lt;a href=&quot;https://sw.kovidgoyal.net/kitty/&quot;&gt;Kitty&lt;/a&gt; as my terminal for some time now, and have become quite comfortable with it. Fortunately, it supports scripting what happens when you click a Terminal Hyperlink, so we’ll do just that! The &lt;a href=&quot;https://sw.kovidgoyal.net/kitty/open_actions/&quot;&gt;manual page&lt;/a&gt; lists a lot more things we can do with these clicks, but for now we just care about text editing.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# ~/.config/kitty/open-actions.conf&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# Note this is _not_ included from the main kitty.conf, and is its own file&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;protocol file&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;action launch --&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;=window --&lt;/span&gt;&lt;span&gt;cwd&lt;/span&gt;&lt;span&gt;=current -- zsh -c &lt;/span&gt;&lt;span&gt;&quot;source ~/.zshrc; nvim -- $FILE_PATH&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, any time you use &lt;code&gt;rg&lt;/code&gt; or any of the other hyperlinked commands, all relevant filenames can be Ctrl+Shift+Left-Click-ed to open them in a new window inside the current Kitty tab. &lt;code&gt;protocol file&lt;/code&gt; tells Kitty “any link starting with &lt;code&gt;file://&lt;/code&gt;, use the following action”, and &lt;code&gt;action launch&lt;/code&gt; tells Kitty exactly how to launch our editor.&lt;/p&gt;
&lt;p&gt;You may be wondering, “why not just use &lt;code&gt;$EDITOR -- $FILE_PATH&lt;/code&gt;, why is &lt;code&gt;$SHELL&lt;/code&gt; involved at all?” And that’s a great question. See, there’s a lot of stuff going on in my &lt;code&gt;.zshrc&lt;/code&gt;, from &lt;a href=&quot;https://brew.sh/&quot;&gt;homebrew&lt;/a&gt;/&lt;a href=&quot;https://github.com/nix-darwin/nix-darwin&quot;&gt;nix-darwin&lt;/a&gt; globally installed packages, to per-directory workspaces made with &lt;a href=&quot;https://direnv.net/&quot;&gt;direnv&lt;/a&gt;/&lt;a href=&quot;https://mise.jdx.dev/&quot;&gt;mise-en-place&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Needless to say, my system is pretty bare without its &lt;code&gt;$PATH&lt;/code&gt; filled to the brim with all these goodies. In fact, many of my Neovim plugins require it: I need &lt;code&gt;rg&lt;/code&gt; &amp;amp; &lt;code&gt;fd&lt;/code&gt; for &lt;a href=&quot;https://github.com/folke/snacks.nvim&quot;&gt;snacks.nvim&lt;/a&gt;, language servers for &lt;a href=&quot;https://github.com/Saghen/blink.cmp&quot;&gt;blink.cmp&lt;/a&gt;, &lt;code&gt;git&lt;/code&gt; for &lt;a href=&quot;https://github.com/tpope/vim-fugitive&quot;&gt;fugitive.vim&lt;/a&gt;, y’know, the works. However (for myriad reasons beyond the scope of this post), when launching a new window, Kitty isn’t &lt;em&gt;quite&lt;/em&gt; smart enough to copy environment variables like &lt;code&gt;$PATH&lt;/code&gt; from the currently active window&lt;sup&gt;&lt;a href=&quot;#user-content-fn-env&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. So, we just have to re-compute our &lt;code&gt;$PATH&lt;/code&gt; before launching our editor. The reason I do &lt;code&gt;-c &quot;source ~/.zshrc&quot;&lt;/code&gt; instead of &lt;code&gt;-i&lt;/code&gt; is for speed; launching zsh first means there will be a brief flash of shell before the editor launches, and the former approach seems to minimize that flash.&lt;/p&gt;
&lt;h2&gt;The Complications&lt;/h2&gt;
&lt;p&gt;“Well golly gee willikers,” I hear you say, “Being able to open inside a new &lt;em&gt;Kitty&lt;/em&gt; window sure is dandy and all, but what I really want to do is open files I click on inside a new &lt;em&gt;Neovim&lt;/em&gt; tab, in an existing Kitty window &lt;img src=&quot;https://www.hazelduvall.dev/static/emoji/um-ackshully.png&quot; alt=&quot;nerd &apos;um ackshully&apos; emoji&quot; /&gt;” Well fear not, dear reader, because I thought those same thoughts &amp;amp; have just the solution for you! This requires a just a bit more setup, which I have put together in the form of a “simple” shell script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#!/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# Ignore the ~/.local/bin directory when searching for nvim&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# (assumes this script has been placed at ~/.local/bin/nvim)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; PATH&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; $PATH &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; sed&lt;/span&gt;&lt;span&gt; -E&lt;/span&gt;&lt;span&gt; -e&lt;/span&gt;&lt;span&gt; &quot;s|${&lt;/span&gt;&lt;span&gt;HOME&lt;/span&gt;&lt;span&gt;}/.local/bin(:\|$)||&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt; -z&lt;/span&gt;&lt;span&gt; &quot;${&lt;/span&gt;&lt;span&gt;KITTY_TAB_ID&lt;/span&gt;&lt;span&gt;}&quot;&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  # If running in Kitty, use the tab ID to get the pipe for the Neovim instance for that tab.&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  pipe&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;${&lt;/span&gt;&lt;span&gt;XDG_CACHE_HOME&lt;/span&gt;&lt;span&gt;:-&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;HOME&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;}/nvim/server-${&lt;/span&gt;&lt;span&gt;KITTY_TAB_ID&lt;/span&gt;&lt;span&gt;}.pipe&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt; -S&lt;/span&gt;&lt;span&gt; &quot;${&lt;/span&gt;&lt;span&gt;pipe&lt;/span&gt;&lt;span&gt;}&quot;&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # Launch instance if there isn&apos;t one already&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;$1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;-k&quot;&lt;/span&gt;&lt;span&gt; ] &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;$1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;--kitty-remote&quot;&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      shift&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    nvim&lt;/span&gt;&lt;span&gt; --listen&lt;/span&gt;&lt;span&gt; &quot;${&lt;/span&gt;&lt;span&gt;pipe&lt;/span&gt;&lt;span&gt;}&quot;&lt;/span&gt;&lt;span&gt; &quot;&lt;/span&gt;&lt;span&gt;$@&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  else&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # Pipe already exists&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;$1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;-k&quot;&lt;/span&gt;&lt;span&gt; ] &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;$1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;--kitty-remote&quot;&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      # Open files in existing instance&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      shift&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      nvim&lt;/span&gt;&lt;span&gt; --server&lt;/span&gt;&lt;span&gt; &quot;${&lt;/span&gt;&lt;span&gt;pipe&lt;/span&gt;&lt;span&gt;}&quot;&lt;/span&gt;&lt;span&gt; --remote-tab&lt;/span&gt;&lt;span&gt; &quot;&lt;/span&gt;&lt;span&gt;$@&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      # Launch new, non-remote instance&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      nvim&lt;/span&gt;&lt;span&gt; &quot;&lt;/span&gt;&lt;span&gt;$@&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    fi&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  # If not running in kitty, pass through arguments unchanged&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  nvim&lt;/span&gt;&lt;span&gt; &quot;&lt;/span&gt;&lt;span&gt;$@&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are comments inline explaining most of it, but to summarize:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use a unique-per-tab ID to construct a path inside a directory for Neovim to listen on&lt;/li&gt;
&lt;li&gt;If such a path doesn’t already exist, starts Neovim listening on that path&lt;/li&gt;
&lt;li&gt;If such a path &lt;em&gt;does&lt;/em&gt; exist, only connect to it when a special command-line flag is given.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I chose the &lt;code&gt;-k&lt;/code&gt; flag (shorthand for &lt;code&gt;--kitty-remote&lt;/code&gt;), which also happens to be unused for all of &lt;code&gt;nvim&lt;/code&gt;, &lt;code&gt;rg&lt;/code&gt;, &lt;code&gt;fd&lt;/code&gt;, and &lt;code&gt;eza&lt;/code&gt; surprisingly, that I then use in my updated Kitty &lt;code&gt;open-actions.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# ~/.config/kitty/open-actions.conf&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;protocol file&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;action launch --type=window --cwd=current -- $SHELL -c &quot;source ~/.zshrc; nvim --kitty-remote $FILE_PATH&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This replaces the &lt;code&gt;protocol&lt;/code&gt;/&lt;code&gt;action&lt;/code&gt; block we had previously. We get rid of the &lt;code&gt;--&lt;/code&gt; because the &lt;code&gt;--remote-tab&lt;/code&gt; used in our script already treats all remaining arguments as filenames.&lt;/p&gt;
&lt;p&gt;The nice part about having this as a full-blown script, as opposed to just a shell function, is that we can use it with &lt;code&gt;xargs&lt;/code&gt;, leading to some even crazier aliases:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# ~/.zshrc&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; rgim&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  extra_args&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;$1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;-k&quot;&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    shift&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    extra_args&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;-k&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  rg&lt;/span&gt;&lt;span&gt; -l&lt;/span&gt;&lt;span&gt; &quot;&lt;/span&gt;&lt;span&gt;$@&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;span&gt; xargs&lt;/span&gt;&lt;span&gt; nvim&lt;/span&gt;&lt;span&gt; ${extra_args}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; rgkm&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;rgim -k&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Meaning, &lt;code&gt;rgkm foobar&lt;/code&gt; will open all files containing the string “foobar” in separate tabs in an existing Neovim pane. Or, you can &lt;code&gt;rg foobar&lt;/code&gt; to see the matches before clicking on the individual filesnames, and they will open in the existing Neovim just the same. Magical!!&lt;/p&gt;
&lt;h3&gt;Notes On Getting &lt;code&gt;$KITTY_TAB_ID&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Unfortunately, dear reader, I may have pulled a fast one on you in the previous section; we are not done, there is one block remaining in this tower of shell scripts. Kitty only provides a unique-per-window-ID, &lt;code&gt;$KITTY_WINDOW_ID&lt;/code&gt;, where a “window” is not an OS window but rather a split within a given tab. We require a unique-per-tab-ID instead, thus we are forced to calculate it by hand:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# ~/.zshrc&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; [[ &lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt; -v KITTY_TAB_ID ]] &amp;amp;&amp;amp; (( $&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;commands[kitten] )) &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  # If not already calculated, define KITTY_TAB_ID from our built-in KITTY_WINDOW_ID&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  export&lt;/span&gt;&lt;span&gt; KITTY_TAB_ID&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;$(&lt;/span&gt;&lt;span&gt;kitten&lt;/span&gt;&lt;span&gt; @ ls &lt;/span&gt;&lt;span&gt;--match&lt;/span&gt;&lt;span&gt; &quot;id:${&lt;/span&gt;&lt;span&gt;KITTY_WINDOW_ID&lt;/span&gt;&lt;span&gt;}&quot; &lt;/span&gt;&lt;span&gt;2&amp;gt;&lt;/span&gt;&lt;span&gt; /dev/null &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; jq&lt;/span&gt;&lt;span&gt; &apos;.[0].tabs[0].id&apos;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For performance, this uses some zsh-isms to check if the variable hasn’t been defined already &amp;amp; we have the &lt;code&gt;kitten&lt;/code&gt; command, in order to keep that shell startup time nice &amp;amp; fast. This requires you to have &lt;code&gt;allow_remote_control yes&lt;/code&gt; in your &lt;code&gt;~/.config/kitty/kitty.conf&lt;/code&gt; for the &lt;code&gt;kitten @ ls&lt;/code&gt; command to work. A little bit of extra gnarliness to an already-pretty-gnarly setup, but in the end it is just a few lines so whatever (:&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;These instructions have been tailored for the combination of Kitty + zsh + Neovim, but I’m fairly confident they can be adapted for most other shells/editors running in Kitty too. Not too sure about other terminals though, you might have a harder time scripting the mouse click than in Kitty. I do also recommend checking out &lt;a href=&quot;https://jyn.dev/how-i-use-my-terminal/&quot;&gt;jyn’s original post&lt;/a&gt; for further inspiration on terminal-agnostic approaches, doing the scripting inside &lt;code&gt;tmux&lt;/code&gt; instead perhaps. Though whatever you end up doing, I highly recommend writing some of it yourself, because it is a very good learning experience&lt;sup&gt;&lt;a href=&quot;#user-content-fn-experience&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;And that, my friends, is all I have for you today. Take care &amp;amp; stay frosty 👍&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Though maybe there’s hope with this &lt;a href=&quot;https://github.com/eza-community/eza/pull/1664&quot;&gt;latest PR&lt;/a&gt;… &lt;a href=&quot;#user-content-fnref-eza&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trust me, I tried &lt;em&gt;hard&lt;/em&gt;. There is sort of a way to copy environments from existing windows using a &lt;a href=&quot;https://sw.kovidgoyal.net/kitty/remote-control/#cmdoption-kitten-launch-copy-env&quot;&gt;&lt;code&gt;kitten @ launch&lt;/code&gt;&lt;/a&gt;, but it didn’t work for launching commands in new windows for whatever reason. The next-best thing is to recreate the environment that I actually care about from scratch. &lt;a href=&quot;#user-content-fnref-env&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use of time, however? Who’s to say :) &lt;a href=&quot;#user-content-fnref-experience&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>programming</category></item><item><title>It&apos;s Very Hard To Get LLMs To _Not_ Respond To Messages</title><link>https://www.hazelduvall.dev/blog/posts/2025-08-21-its-very-hard-to-get-llms-to-not-respond.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2025-08-21-its-very-hard-to-get-llms-to-not-respond.html</guid><description>A summary of some experiments trying to get an LLM to not respond when faced with a message by a user.</description><pubDate>Thu, 21 Aug 2025 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Being upfront: all these experiments were done by my coworker &lt;a href=&quot;https://www.linkedin.com/in/jacob-fancher/&quot;&gt;Jacob Fancher&lt;/a&gt; (&lt;a href=&quot;https://github.com/jfancher&quot;&gt;GitHub&lt;/a&gt;), I’m just writing it up because I think it’s cool :)&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;At &lt;a href=&quot;https://ro.am/&quot;&gt;Roam&lt;/a&gt;, we have an AI assistant called &lt;a href=&quot;https://ro.am/on-it&quot;&gt;“On-It!”&lt;/a&gt; that, among other things, can open a chat between two users, with itself in the middle to close out any tasks discussed:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Solmi: Hello, just wanted to say hello on behalf of Will Hou!
Will Hou: can we hide the voice button here in relay chats?
Solmi: Will Hou is asking if it&amp;amp;#x27;s possible to hide the voice button in relay chats.
Me: Yes
Solmi: Thank you! I&amp;amp;#x27;ve forwarded your response to Will Hou. The task is now closed.&quot; loading=&quot;lazy&quot; width=&quot;1462&quot; height=&quot;870&quot; src=&quot;/_astro/2025-08-20-screenshot_HQWkA.webp&quot; /&gt;
&lt;sup&gt;&lt;a href=&quot;#user-content-fn-solmi&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, this can lead to some pretty stilted conversations; the AI butts in after every message as if it were addressed to it directly, even when the users are pretty clearly just talking to each other. The above example is mostly fine, but for longer conversations it gets really annoying. Turns out, our code had no way for an AI to refuse to answer a message, so we set out to fix that.&lt;/p&gt;
&lt;h2&gt;Things That Don’t Work&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sentinel string&lt;/strong&gt;: Telling the AI, to effect, “if you think you shouldn’t respond, reply ‘No comment’”, or other such strings. The AI’s response would be compared against the sentinel, and the message not sent if it matched.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optional tool call&lt;/strong&gt;: Telling the AI, “If you think you shouldn’t respond, use this &lt;code&gt;dont_respond&lt;/code&gt; tool call instead of sending a message.” The AI already knew about a bunch of other tool calls (for scheduling meetings, creating new tasks, etc.), so if we saw it make this one, we would not send the message.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enforced tool call&lt;/strong&gt;: Making it so there are both &lt;code&gt;respond&lt;/code&gt; &amp;amp; &lt;code&gt;dont_respond&lt;/code&gt; tool calls, and only by using the &lt;code&gt;respond&lt;/code&gt; tool call can the AI send messages back to the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unfortunately, none of these approaches worked! No matter what, the AI would do whatever it could to send a message back to a user, even entirely useless ones as before.&lt;/p&gt;
&lt;h3&gt;Hypothesis For Why&lt;/h3&gt;
&lt;p&gt;Our AI is built on top of OpenAI’s ChatGPT API, which is LLM-based&lt;sup&gt;&lt;a href=&quot;#user-content-fn-llms&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. Modern LLMs innately expect to complete a message by responding to it, and get very angsty when they can’t respond. This is because the process for turning a “base” model (just trained on raw text) into something like ChatGPT involves a lot of fine-tuning on chat-specific data, enforcing “roles” like &lt;code&gt;user&lt;/code&gt; (for messages input by the user) and &lt;code&gt;assistant&lt;/code&gt; (for responses created by the AI). OpenAI’s API even &lt;a href=&quot;https://platform.openai.com/docs/guides/conversation-state?api-mode=responses#manually-manage-conversation-state&quot;&gt;encodes these roles directly&lt;/a&gt; so you don’t have to manually format the input, it’s all done under the hood for you.&lt;/p&gt;
&lt;p&gt;So, the fine-tuning makes an LLM always want to put an &lt;code&gt;assistant&lt;/code&gt; message after every &lt;code&gt;user&lt;/code&gt; message, no matter what. No amount of prompt engineering can counteract an LLM’s innate drive to respond to a user; even the “Enforced Tool Call” approach is treated as merely a fancy response format. In order get the AI to not respond, we need a different prompting strategy entirely.&lt;/p&gt;
&lt;h2&gt;The Thing That Does Work&lt;/h2&gt;
&lt;p&gt;We landed on a 2-step approach: first, we have an “evaluator” prompt with instructions to decide whether or not the AI should respond, outputting into a structured JSON object containing just a boolean &lt;code&gt;should_respond&lt;/code&gt; field. Then, we have the normal “responder” prompt that does the rest of the work, crafting a response &amp;amp; making tool calls. Separating out the prompts like this frees each part to think about only what it needs to; the “evaluator” is happy saying &lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt; as a complete response, and the “responder” only has to think about &lt;em&gt;what&lt;/em&gt; it should respond with, which usually overpowers any thought as to &lt;em&gt;if&lt;/em&gt; it should respond.&lt;/p&gt;
&lt;p&gt;Unfortunately, doing it in two stages like this is a wee bit more expensive, and requires a non-trivial change to our backend, so we decided not to go through with it for now. Still, good to know what we should do whenever this comes up again!&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Solmi, Will’s dog, is also featured in &lt;a href=&quot;2024-03-23-wow-another-chrome-bug.html&quot;&gt;another post of mine&lt;/a&gt; talking about a Chrome rendering bug (now fixed). Thank you for helping us debug our software, Solmi &amp;lt;3 &lt;a href=&quot;#user-content-fnref-solmi&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Really, what AI &lt;em&gt;isn’t&lt;/em&gt; LLM-based nowadays… &lt;a href=&quot;#user-content-fnref-llms&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>AI</category></item><item><title>CSS Flex, Grid, and Containing Blocks</title><link>https://www.hazelduvall.dev/blog/posts/2025-06-25-flex-grid-and-containing-blocks.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2025-06-25-flex-grid-and-containing-blocks.html</guid><description>A quick dive into the intricacies of how some intuitive-seeming CSS features _actually_ work, in order to build a better mental model when building designs that use them.</description><pubDate>Wed, 25 Jun 2025 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Changing from &lt;code&gt;display: flex;&lt;/code&gt; to &lt;code&gt;display: grid;&lt;/code&gt; can break certain designs due to differences in how containing blocks work between them. If you read that and went “what does that even mean??”, keep reading.&lt;/p&gt;
&lt;h2&gt;The Bug&lt;/h2&gt;
&lt;p&gt;This toy example is based on a real bug that completely slipped under my radar in code review, so I am highly motivated to write this blog post &amp;amp; understand in meticulous detail &lt;em&gt;exactly&lt;/em&gt; what’s going on with it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.Container&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;solid&lt;/span&gt;&lt;span&gt; black&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  padding&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  contain&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;strict&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  display&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;flex&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  flex-direction&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;column&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.ChatContainer&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  width&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  display&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;flex&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  flex-direction&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;column&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  gap&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.Chats&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  background&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;lightgray&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  flex&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; 200&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  min-height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;lh;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  overflow-y&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  display&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;flex&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  flex-direction&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;column&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.Composer&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;dashed&lt;/span&gt;&lt;span&gt; grey&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  padding&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  max-height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  overflow-y&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Container&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;ChatContainer&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Chats&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;There’s a bunch of text here&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;Just so that it scrolls&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;Mostly line breaks perhaps&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;yeah&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;line breaks&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;:)&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Composer&quot;&lt;/span&gt;&lt;span&gt; contenteditable&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;true&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;You can type in this box, try it out!&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;There’s a bunch of text here&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Just so that it scrolls&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Mostly line breaks perhaps&lt;/p&gt;&lt;br /&gt;&lt;p&gt;yeah&lt;/p&gt;&lt;br /&gt;&lt;p&gt;line breaks&lt;/p&gt;&lt;br /&gt;&lt;p&gt;:)&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;You can type in this box, try it out!&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;p&gt;It’s been simplified a lot, but it’s representative of the situation we found ourselves in: some editable text below some static text, where both texts are scrollable, and the amount of editable text changes how much room the static text is given. There’s nothing&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; wrong with it yet, just setting the scene/giving a baseline.&lt;/p&gt;
&lt;p&gt;Next, let’s add a sidebar, changing &lt;code&gt;.Container&lt;/code&gt; from &lt;code&gt;display: flex;&lt;/code&gt; to &lt;code&gt;display: grid;&lt;/code&gt; so as to not add another nested div:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.Container.v2&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  display&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;grid&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  grid-template-columns&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;fr&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  gap&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.Sidebar&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  background&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;orange&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;There’s a bunch of text here&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Just so that it scrolls&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Mostly line breaks perhaps&lt;/p&gt;&lt;br /&gt;&lt;p&gt;yeah&lt;/p&gt;&lt;br /&gt;&lt;p&gt;line breaks&lt;/p&gt;&lt;br /&gt;&lt;p&gt;:)&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;You can type in this box, try it out!&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;p&gt;Uh-oh, big trouble!! There’s some bad overflow going on here, and we can no longer see &lt;code&gt;.Composer&lt;/code&gt;! Why is this? We set &lt;code&gt;width: 100%; height: 100%;&lt;/code&gt; on &lt;code&gt;.ChatContainer&lt;/code&gt; after all, so it should be the exact same size as its parent &lt;code&gt;.Container&lt;/code&gt;, right??&lt;/p&gt;
&lt;h2&gt;Time To Do Some Reading&lt;/h2&gt;
&lt;p&gt;Wait a minute… &lt;code&gt;width: 100%;&lt;/code&gt;… so why can we still see &lt;code&gt;.Sidebar&lt;/code&gt;?. Checking the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/width&quot;&gt;MDN documentation for &lt;code&gt;width&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;percentage&amp;gt;&lt;/code&gt;: Defines the width as a percentage of the containing block’s width&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;OK, and a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_display/Containing_block&quot;&gt;containing block&lt;/a&gt;?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Many developers believe that the containing block of an element is always the content area of its parent, but that isn’t necessarily true.&lt;/p&gt;
&lt;p&gt;[…]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If the &lt;code&gt;position&lt;/code&gt; property is &lt;code&gt;static&lt;/code&gt;, &lt;code&gt;relative&lt;/code&gt;, or &lt;code&gt;sticky&lt;/code&gt;, the containing block is formed by the edge of the &lt;em&gt;content box&lt;/em&gt; of the nearest ancestor element that is either a block container (such as an inline-block, block, or list-item element) or establishes a formatting context (such as a table container, flex container, grid container, or the block container itself).&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, we have a &lt;code&gt;flex&lt;/code&gt;/&lt;code&gt;grid&lt;/code&gt; container, so looks like it’s spec-reading time for us. Er, more like spec-Ctrl-F-ing for “containing block”, but hey :P&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&quot;https://drafts.csswg.org/css-flexbox/&quot;&gt;CSS Flexible Box Layout Module Level 1&lt;/a&gt;, Paragraph 3:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Flex containers form a containing block for their contents exactly like block containers do.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://www.hazelduvall.dev/static/2025-06-20/flex-containing-block.png&quot; alt=&quot;flex containing block diagram&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The containing block for the &lt;code&gt;display: flex;&lt;/code&gt; is &lt;em&gt;exactly&lt;/em&gt; the area of its content element, a.k.a. “the normal thing”. So, doing &lt;code&gt;width: 100%; height: 100%&lt;/code&gt; in a child element was doing what we expected: setting our width/height to exactly that of a parent.&lt;/p&gt;
&lt;p&gt;Next, reading from &lt;a href=&quot;https://drafts.csswg.org/css-grid/&quot;&gt;CSS Grid Layout Module Level 2&lt;/a&gt;, Paragraph 3.3:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A grid item’s grid area forms the containing block into which it is laid out.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://www.hazelduvall.dev/static/2025-06-20/grid-containing-blocks.png&quot; alt=&quot;grid containing block diagram&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Aha! As we observed before, there’s no longer one big containing block that spans the full width of the div, but rather individual containing blocks created for each grid item. Once we get into layouts that span multiple rows/columns, I can definitely see why this was done: it makes laying out the item within the grid area a lot easier; knowing the width/height of the area is much more important than knowing the width/height of the parent grid.&lt;/p&gt;
&lt;p&gt;But for now, I mostly just care about one thing: why the &lt;code&gt;height&lt;/code&gt; do that??&lt;/p&gt;
&lt;h2&gt;Synthesis&lt;/h2&gt;
&lt;p&gt;Let’s recap what we know:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;.ChatContainer&lt;/code&gt; has &lt;code&gt;height: 100%;&lt;/code&gt;, meaning it will be as tall as its containing block.&lt;/li&gt;
&lt;li&gt;Because it’s a grid item, &lt;code&gt;.ChatContainer&lt;/code&gt;’s containing block will be its grid area.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Solving This The Correct Way&lt;/h3&gt;
&lt;p&gt;If not specified, the default values for grid rows are:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;.Container.v2&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  grid-template-rows&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;none&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  grid-auto-rows&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Meaning, all the rows are automatically inserted and have height &lt;code&gt;auto&lt;/code&gt;. &lt;em&gt;Meaning&lt;/em&gt;, the containing block will try to resolve its height based on the content. &lt;em&gt;&lt;strong&gt;Meaning&lt;/strong&gt;&lt;/em&gt;, our &lt;code&gt;height: 100%&lt;/code&gt; now does nothing, effectively the same as if it were &lt;code&gt;height: auto&lt;/code&gt; itself. Whoops!&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;To fix this, we just need to force the grid rows to have a specified height. At the level of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-rows&quot;&gt;&lt;code&gt;grid-template-rows&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;percentage&amp;gt;&lt;/code&gt;: Is a non-negative &lt;code&gt;&amp;lt;percentage&amp;gt;&lt;/code&gt; value, relative to the block size of the grid container.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So a row of height &lt;code&gt;100%&lt;/code&gt; will make the grid area’s containing block be the correct size, making our &lt;code&gt;height: 100%&lt;/code&gt; propagate thru as intended, and the design will be fixed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.Container.v3&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  display&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;grid&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  grid-template-columns&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;fr&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  grid-template-rows&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  gap&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;There’s a bunch of text here&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Just so that it scrolls&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Mostly line breaks perhaps&lt;/p&gt;&lt;br /&gt;&lt;p&gt;yeah&lt;/p&gt;&lt;br /&gt;&lt;p&gt;line breaks&lt;/p&gt;&lt;br /&gt;&lt;p&gt;:)&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;You can type in this box, try it out!&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;Solving This The Cool Way&lt;/h3&gt;
&lt;p&gt;I do love the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/contain&quot;&gt;&lt;code&gt;contain&lt;/code&gt;&lt;/a&gt; property, so I couldn’t resist showing off a solution that uses it too :)&lt;/p&gt;
&lt;p&gt;Thinking a bit, the problem isn’t necessarily that &lt;code&gt;.ChatContainer&lt;/code&gt; gets &lt;code&gt;height: auto;&lt;/code&gt;, the problem is what happens after, when the content inside forces &lt;code&gt;.ChatContainer&lt;/code&gt; to become taller than its parent to contain all that content. But what if there were a way to say “only size yourself based on elements above you, ignoring input from all those below you”? Turns out that’s exactly what &lt;code&gt;contain: size;&lt;/code&gt; does!!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.ChatContainer.v4&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  width&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  contain&lt;/span&gt;&lt;span&gt;: size;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Container v2&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;ChatContainer v4&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Chats&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;There’s a bunch of text here&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;Just so that it scrolls&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;Mostly line breaks perhaps&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;yeah&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;line breaks&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;br&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;:)&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Composer&quot;&lt;/span&gt;&lt;span&gt; contenteditable&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;true&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;You can type in this box, try it out!&amp;lt;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Sidebar&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;There’s a bunch of text here&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Just so that it scrolls&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Mostly line breaks perhaps&lt;/p&gt;&lt;br /&gt;&lt;p&gt;yeah&lt;/p&gt;&lt;br /&gt;&lt;p&gt;line breaks&lt;/p&gt;&lt;br /&gt;&lt;p&gt;:)&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;You can type in this box, try it out!&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;p&gt;This approach is likely a little more brittle than the explicit grid approach, but I think it’s cooler, and that’s what matters 😎&lt;/p&gt;
&lt;p&gt;OK that’s it, hope you enjoyed &amp;amp; learned something today ^w^&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;OK that’s a lie, I would definitely not recommend using anything like this in production, but it works well enough for demonstration purposes here :) &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This is often a big problem with &lt;code&gt;height: 100%&lt;/code&gt; bounds in general: if you introduce &lt;em&gt;any&lt;/em&gt; layer of &lt;code&gt;height: auto&lt;/code&gt; indirection in between, they tend to break like this. Switching from &lt;code&gt;display: flex;&lt;/code&gt; to &lt;code&gt;display: grid;&lt;/code&gt; is just an extreme example of this I guess :P &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>programming</category><category>Web</category></item><item><title>The AIs Seem To Like One Of My Posts; Why Is That?</title><link>https://www.hazelduvall.dev/blog/posts/2025-06-07-the-ais-seem-to-like-my-post-why-is-that.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2025-06-07-the-ais-seem-to-like-my-post-why-is-that.html</guid><description>Musings on why exactly one of my blog posts has steadily gotten hits to it from many different AI sources over the past few months.</description><pubDate>Sat, 07 Jun 2025 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of my past posts, &lt;a href=&quot;2024-09-14-safari-css-bug.html&quot;&gt;“A Safari aspect-ratio CSS Bug”&lt;/a&gt;, has had very steadily growing traffic to it for a few months now. Mostly from Google, as a given, but ChatGPT, Claude, &amp;amp; Perplexity are all in there as referring domains too.&lt;/p&gt;
&lt;p&gt;To be clear, I’m pretty pleased with this! I’m happy that people are continuing to find my work useful, and glad that I bothered to write down my solution 9 months ago. But, it’s not like I really do any marketing for this thing? &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7330411629643255809/&quot;&gt;This&lt;/a&gt; (LinkedIn wall sorry) doesn’t count. So, it’s all just the algorithms out there deciding my words are tasty &amp;amp; serving it up to people of their own accord. My curiousity cannot be sated. &lt;em&gt;Why?&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Hypotheses For Why Algorithms Like It&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;It’s very short&lt;/li&gt;
&lt;li&gt;It’s very structured&lt;/li&gt;
&lt;li&gt;It efficiently answers “How Do I Do X?” which may be the exact question the user has typed in&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I didn’t &lt;em&gt;really&lt;/em&gt; optimize for these things when writing that post, it just sorta ended up that way. But! Those turned out to be pretty good properties to have in a post regardless, even if you’re not an algorithm. To test these hypotheses, I would need to write more blog posts, but alas, i am merely a channel for the energies of the divine muses, &amp;amp; their whims r fickle. anyways&lt;/p&gt;
&lt;h2&gt;Why &lt;em&gt;I&lt;/em&gt; Like It&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;It’s interactive&lt;/li&gt;
&lt;li&gt;It includes not only the &lt;em&gt;what&lt;/em&gt;, but a plausible explanation for the &lt;em&gt;why&lt;/em&gt;, helping you learn something about browsers/CSS after you finish reading/experimenting&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Neither of these are things you get by reading the AI output&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Which is why I’m glad that people actually clicked thru to the source! I like writing these posts for people, so I hope the state of things will be “peope use AI to find the posts” and not “the AIs read the posts &amp;amp; tell the people what was in the posts”, tho sometimes it seems we’re headed in the latter direction, ah well.&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In a perfect world: yes the perfect AI assistant could do both. But we do not live in a perfect world. The common assistants don’t do arbitrary HTML/CSS-injected demos (good!!!), and the summaries &lt;em&gt;will&lt;/em&gt; miss the subtleties of what’s going on in this article. Please just read the original it’s so short. &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>daily thoughts</category><category>AI</category></item><item><title>node-webrtc v0.9.0 Released!</title><link>https://www.hazelduvall.dev/blog/posts/2025-05-16-node-webrtc-0-9-0-released.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2025-05-16-node-webrtc-0-9-0-released.html</guid><description>Extra notes to the changelog I made for a somewhat-popular open-source package I maintain</description><pubDate>Fri, 16 May 2025 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow!! I can’t believe it’s been over 1.5 years since I &lt;a href=&quot;2023-10-11-im-a-maintainer-now.html&quot;&gt;became the maintainer of node-webrtc&lt;/a&gt;. Feels a lot longer than that somehow :) Finally at a point where it feels like “my” codebase that I know every square inch of.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/@roamhq/wrtc/v/0.9.0&quot;&gt;This release&lt;/a&gt; has been a long time coming, and contains a few major improvements over the previous v0.8.0 release:&lt;/p&gt;
&lt;h3&gt;No More Compiler Warnings&lt;/h3&gt;
&lt;p&gt;It had always bothered me when Clang spat out a bunch of compiler warnings when building the project. It was a lot of work over many other commits, but I recorded &lt;a href=&quot;https://github.com/WonderInventions/node-webrtc/commit/c58b90e49042cdee9698dee85177f15f7ecf9d62&quot;&gt;this commit&lt;/a&gt; as the last one in the series. Now, when you build node-webrtc, you don’t get any compiler warnings!&lt;sup&gt;&lt;a href=&quot;#user-content-fn-gcc&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Speaking of building:&lt;/p&gt;
&lt;h3&gt;Unified Build Environments With Nix&lt;/h3&gt;
&lt;p&gt;Previously, I had to do some pretty bespoke stuff on each machine to set up a proper build environment for node-webrtc. Given the number of machines I had, this sucked. This past year, however, I’ve been slowly becoming more familiar with &lt;a href=&quot;https://nix.dev/&quot;&gt;Nix&lt;/a&gt;, to the point where I could create a mildly complex &lt;a href=&quot;https://github.com/WonderInventions/node-webrtc/blob/a806f4ddff5daafd104c1dda7a74cac50fb1cf06/shell.nix&quot;&gt;build envionment definition&lt;/a&gt; to share between my Linux and MacOS machines. I’m most proud of the fact that it’s completely gotten rid of any dependency on the system XCode on MacOS, managing that with Nix is so much nicer holy wow.&lt;/p&gt;
&lt;p&gt;Cross-compilation is still a bit tricky, even with this setup. Here’s what I can do so far:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MacOS arm64 ➡️ MacOS x64&lt;/li&gt;
&lt;li&gt;MacOS x64 ➡️ ️MacOS arm64&lt;/li&gt;
&lt;li&gt;Linux x64 ➡️ Linux arm64&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yeah, not very impressive I know sorry :P My stretch goal is to be able to target anything in {MacOS x64, Linux x64, Linux arm64, Windows x64} all from MacOS arm64, because my M4 Macbook Pro chews through compilation tasks like no one’s business. That’s where I did my main development for:&lt;/p&gt;
&lt;h3&gt;Reducing Memory Errors With Rust-Inspired Lifetime Management&lt;/h3&gt;
&lt;p&gt;Garbage collection in C++ sucks, man. Or more specifically, interfacing with Node’s garbage collection through their API sucks. There’s a lot of stuff to uphold, and because the API was originally written for C, not C++, a lot of stuff &lt;em&gt;really&lt;/em&gt; just wants to be a pointer. I do not know why I had to write my own &lt;a href=&quot;https://github.com/WonderInventions/node-webrtc/blob/a806f4ddff5daafd104c1dda7a74cac50fb1cf06/src/node/ref_ptr.hh&quot;&gt;&lt;code&gt;RefPtr&lt;/code&gt;&lt;/a&gt; class, but I did, and I know too much about C++ constructors because of it.&lt;/p&gt;
&lt;p&gt;That’s really the thing that was missing from the codebase: a concept of ownership, à la Rust. Not properly tracking that would cause destructors to not fire at all (memory leak/hang), or fire too early (segfault), both of which would be caught by some &lt;a href=&quot;https://github.com/WonderInventions/node-webrtc/blob/develop/test/destructor/index.js&quot;&gt;test cases&lt;/a&gt; (massive shoutouts to the previous maintainer &lt;a href=&quot;https://mrkrbrts.com/&quot;&gt;Mark&lt;/a&gt; for writing these tests in the first place!!). My solution for this was to introduce an &lt;a href=&quot;https://github.com/WonderInventions/node-webrtc/blob/a806f4ddff5daafd104c1dda7a74cac50fb1cf06/src/node/wrap.hh&quot;&gt;&lt;code&gt;OwnedWrap&lt;/code&gt;&lt;/a&gt; class, clarifying the existing semantics of the &lt;code&gt;Wrap&lt;/code&gt; class used to create weak references to cached objects.&lt;/p&gt;
&lt;h2&gt;Future Plans?&lt;/h2&gt;
&lt;p&gt;Really, other than a few tricky GC errors &amp;amp; the usual fighting with the build system, I didn’t have too much trouble updating node-webrtc to M98 and Node.JS 22. My hope is that, with a lot of annoyances cleaned up and a lot of knowledge gained, I can finally start making progress on catching up to the latest libwebrtc version. I know there will be some link errors along the way, and I still don’t have a lot of free time to dedicate to this project, but damnit it feels good to finally get out a release. Here’s hoping the next one doesn’t also take a whole year!&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;GCC still gives compiler warnings, unfortunately. I think they’re wrong, though, so shouldn’t be too much trouble to turn them off if I need someday. &lt;a href=&quot;#user-content-fnref-gcc&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>WebRTC</category><category>C++</category><category>Nix</category></item><item><title>More Photography Updates (and RSS)</title><link>https://www.hazelduvall.dev/blog/posts/2025-02-25-more-photography-updates.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2025-02-25-more-photography-updates.html</guid><description>I describe some updates I&apos;ve made to the site, and release 2 more photo collections</description><pubDate>Tue, 25 Feb 2025 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello again! I promise this will be the last time I announce a photography collection here: &lt;a href=&quot;/photography/2024-empire-state.html&quot;&gt;2024: Empire State Building&lt;/a&gt; is my latest set as mentioned in my &lt;a href=&quot;2025-01-11-nyc-photography.html&quot;&gt;previous post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also no, “last time” is not because I’m quitting taking photos or anything like that. It’s just because I’ve finally set up an RSS feed for my photography! Previously, I was worried people might miss when I released those unless I updated here, but now that I have RSS set up for it, any new photography collections I release will show up under the &lt;a href=&quot;/photography/rss.xml&quot;&gt;photography feed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Speaking of RSS, I also did a little digging and found my surfacing of it in my page’s metadata was sorely lacking. I was only advertising it on my main page, not on any of the blog posts themselves, so people wanting to quickly add my site into their feed reader may have been out-of-luck. No longer! I’ve been using RSS a lot more myself recently, so I’m more attuned to things like this now. Most peoples’ sites actually have pretty good RSS support turns out!! You should use RSS, it is excellent, also subscribe to my blog with it :) kthxbye&lt;/p&gt;</content:encoded><category>Photography</category><category>RSS</category></item><item><title>NYC Photography</title><link>https://www.hazelduvall.dev/blog/posts/2025-01-11-nyc-photography.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2025-01-11-nyc-photography.html</guid><description>I unveil my 2024 NYC photo collection</description><pubDate>Sat, 11 Jan 2025 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi! I just released the first of my 2024 NYC photo collections (yes there is another coming). More details on the page itself, &lt;a href=&quot;/photography/2024-nyc.html&quot;&gt;check it out!&lt;/a&gt;&lt;/p&gt;</content:encoded><category>Photography</category></item><item><title>All Javascript Keyboard Shortcut Libraries Are Broken</title><link>https://www.hazelduvall.dev/blog/posts/2025-01-10-all-javascript-keyboard-shortcut-libraries-are-broken.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2025-01-10-all-javascript-keyboard-shortcut-libraries-are-broken.html</guid><description>Either subtly, or not-so-subtly. There is no way to fix the more subtle variant, and the only solution is to Give Up (on supporting a large subset of keyboard shortcuts).</description><pubDate>Fri, 10 Jan 2025 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Either subtly (by using &lt;code&gt;key&lt;/code&gt;), or not-so-subtly (by using &lt;code&gt;code&lt;/code&gt;). There is no way to fix the more subtle variant, and the only solution is to Give Up (on supporting a large subset of keyboard shortcuts).&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;So for work, I was tasked with making it so users could rebind the keyboard shortcuts used in our app. Not too complicated, I just needed to consolidate all the shortcuts into one place so I can split apart the &lt;code&gt;keyboard shortcut -&amp;gt; action&lt;/code&gt; and &lt;code&gt;action -&amp;gt; code that gets run&lt;/code&gt; maps, create a definition for a keyboard shortcut, let users to override the first map in settings, and bam. Don’t even need to use any external libraries, the existing code shows the browser-provided information is more than sufficient! Except wait a minute, I feel like I’m forgetting something…&lt;/p&gt;
&lt;h2&gt;What Is A Keyboard Shortcut?&lt;/h2&gt;
&lt;p&gt;Ah. Those pesky definitional questions. Others may have different, more complex definitions to account for different, more complex scenarios, but for our purposes in our app, a keyboard shortcut is simple:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A keyboard shortcut is one or more modifier keys being pressed when exactly one non-modifier key gets pressed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And while I’m at it, I should probably also define what a modifier key is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A modifier key is any one of the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Shift, aka ⇧&lt;/li&gt;
&lt;li&gt;Control, aka ⌃&lt;/li&gt;
&lt;li&gt;Alt, aka Option, aka ⌥&lt;/li&gt;
&lt;li&gt;Meta, aka Super, aka Windows Key, aka Command, aka ⌘&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’m sure we’ll have to revisit this for Vim mode, whenever a critical number of nerds starts using our platform, but good enough for now.&lt;/p&gt;
&lt;p&gt;We choose this definition because it exactly lines up with the fields in &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent&quot;&gt;KeyboardEvent&lt;/a&gt;: &lt;code&gt;altKey&lt;/code&gt;, &lt;code&gt;ctrlKey&lt;/code&gt;, &lt;code&gt;metaKey&lt;/code&gt;, and &lt;code&gt;shiftKey&lt;/code&gt;. And then one other field for the non-modifier key. One other field… Wait, there’s more than one??&lt;/p&gt;
&lt;h2&gt;More Than One Way To Describe A Key&lt;/h2&gt;
&lt;p&gt;Ignoring all the deprecated ways, there are exactly two fields that describing which non-modifier key was pressed: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code&quot;&gt;&lt;code&gt;code&lt;/code&gt;&lt;/a&gt; (deprecated: &lt;code&gt;keyCode&lt;/code&gt;, &lt;code&gt;which&lt;/code&gt;) and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key&quot;&gt;&lt;code&gt;key&lt;/code&gt;&lt;/a&gt; (deprecated: &lt;code&gt;keyIdentifier&lt;/code&gt;). The linked MDN documentation does a pretty good job at explaining the differences, but i also like to think i am also good at explaining things, so here I go:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;code&lt;/code&gt; is for when you want to write a game, where the position of the keys relative to each other matters.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;key&lt;/code&gt; is for literally everything else. Why? Because otherwise, users on alternative or international layouts would read the incorrect thing when using &lt;code&gt;code&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Great, easy! I’m sure that all the popular libraries will be aware of this and all use &lt;code&gt;key&lt;/code&gt;, then :)&lt;/p&gt;
&lt;h2&gt;Oh No All The Libraries Use &lt;code&gt;code&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Let’s stroll down the &lt;a href=&quot;https://www.npmjs.com/search?page=0&amp;amp;q=keywords%3Ashortcuts&amp;amp;sortBy=downloads_monthly&quot;&gt;top “shortcut” packages on NPM, sorted by monthly downloads&lt;/a&gt;, shall we?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-hotkeys-hook&quot;&gt;react-hotkeys-hook&lt;/a&gt;: &lt;a href=&quot;https://github.com/JohannesKlauss/react-hotkeys-hook/blob/bc55a281f1d212d09de786aeb5cd236c58d9531d/src/isHotkeyPressed.ts#L10&quot;&gt;uses both &lt;code&gt;code&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;key&lt;/code&gt;&lt;/a&gt; in a way that will lead to shortcuts triggering more often than they should.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/mousetrap&quot;&gt;mousetrap&lt;/a&gt;: &lt;a href=&quot;https://github.com/ccampbell/mousetrap/blob/2f9a476ba6158ba69763e4fcf914966cc72ef433/mousetrap.js#L195&quot;&gt;uses &lt;code&gt;which&lt;/code&gt;&lt;/a&gt; which is basically just &lt;code&gt;code&lt;/code&gt; but more deprecated.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/hotkeys-js&quot;&gt;hotkeys-js&lt;/a&gt;: &lt;a href=&quot;https://github.com/jaywcjlove/hotkeys-js/blob/6c0b6a60bdf72e6bb7b38345618c561db25c9382/src/index.js#L231&quot;&gt;uses &lt;code&gt;keyCode&lt;/code&gt;&lt;/a&gt; which is also basically &lt;code&gt;code&lt;/code&gt; but more deprecated, but at least it’s less deprecated than &lt;code&gt;which&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/tinykeys&quot;&gt;tinykeys&lt;/a&gt;: &lt;a href=&quot;https://github.com/jamiebuilds/tinykeys/blob/fcf253635231925d660fd6699c9a783ecd038faf/src/tinykeys.ts#L131-L132&quot;&gt;supports both &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;key&lt;/code&gt;&lt;/a&gt; but defaults to &lt;code&gt;key&lt;/code&gt;; the user has to explicitly specify a string like &lt;code&gt;KeyA&lt;/code&gt; if they want to match on &lt;code&gt;code&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;Wow, it’s our first good one! I honestly really like this choice.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/combokeys&quot;&gt;combokeys&lt;/a&gt;: &lt;a href=&quot;https://github.com/avocode/combokeys/blob/bdacdfd37972ca9aef1d2bc52a2dc58dc8c469c4/helpers/characterFromEvent.js#L50&quot;&gt;uses &lt;code&gt;which&lt;/code&gt;&lt;/a&gt;, with &lt;a href=&quot;https://github.com/avocode/combokeys/blob/bdacdfd37972ca9aef1d2bc52a2dc58dc8c469c4/Combokeys/prototype/handleKeyEvent.js#L18&quot;&gt;a fallback to &lt;code&gt;keyCode&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-hot-keys&quot;&gt;react-hot-keys&lt;/a&gt;: &lt;a href=&quot;https://github.com/jaywcjlove/react-hotkeys/blob/09f8ea5e328bb9218f039b3649fd28d2561f0c60/src/index.tsx#L3&quot;&gt;just uses hotkeys-js internally&lt;/a&gt;, which used &lt;code&gt;keyCode&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-shortcuts&quot;&gt;react-shortcuts&lt;/a&gt;: &lt;a href=&quot;https://github.com/avocode/react-shortcuts/blob/c02d2bff6a7323a37fe08162b4317c3c732bbaac/src/component/shortcuts.js#L3&quot;&gt;just uses combokeys internally&lt;/a&gt;, which used &lt;code&gt;which&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@discourse/itsatrap&quot;&gt;@discourse/itsatrap&lt;/a&gt;: is a fork of mousetrap and &lt;a href=&quot;https://github.com/discourse/itsatrap/blob/1967b6dd17bbc2f93af336cadfc8ad34fba32c89/itsatrap.js#L215&quot;&gt;still uses &lt;code&gt;which&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/v-hotkey&quot;&gt;v-hotkey&lt;/a&gt;: &lt;a href=&quot;https://github.com/Dafrok/v-hotkey/blob/a7bb78dc8887557b7867d627c497933fe5b00859/src/helpers.js#L44&quot;&gt;uses &lt;code&gt;keyCode&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/ng-keyboard-shortcuts&quot;&gt;ng-keyboard-shortcuts&lt;/a&gt;: &lt;a href=&quot;https://github.com/omridevk/ng-keyboard-shortcuts/blob/de0a5df1310302a8d919677ca300b7e2a578a23c/libs/ng-keyboard-shortcuts/src/lib/ng-keyboard-shortcuts.service.ts#L358&quot;&gt;uses &lt;code&gt;which&lt;/code&gt; with a fallback to &lt;code&gt;keyCode&lt;/code&gt;&lt;/a&gt; and is also the one of the most horrifying Javascript codebases I’ve seen.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@ngneat/hotkeys&quot;&gt;@ngneat/hotkeys&lt;/a&gt;: &lt;a href=&quot;https://github.com/ngneat/hotkeys/blob/a9c011a484bbdcfa4b13db990a8bb935c65d230b/projects/ngneat/hotkeys/src/lib/hotkeys.service.ts#L101&quot;&gt;uses &lt;code&gt;key&lt;/code&gt;&lt;/a&gt;. Not quite as horrifying as the previous, but comes close. Angular projects man…&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/shortcuts&quot;&gt;shortcuts&lt;/a&gt;: Somehow has more downloads than its underlying library, &lt;a href=&quot;https://www.npmjs.com/package/shosho&quot;&gt;shosho&lt;/a&gt;, which &lt;a href=&quot;https://github.com/fabiospampinato/shosho/blob/28c00ed1f1a29b791ff3860fe87919ebc08d576c/src/index.ts#L49-L51&quot;&gt;uses &lt;code&gt;code&lt;/code&gt; with a fallback to &lt;code&gt;key&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@sofie-automation/sorensen&quot;&gt;@sofie-automation/sorensen&lt;/a&gt;: &lt;a href=&quot;https://github.com/nrkno/sorensen/blob/dc1e16a0f6a8e94fde1f1039c69a2cbedaf70c43/src/index.ts#L522&quot;&gt;uses &lt;code&gt;code&lt;/code&gt;&lt;/a&gt;, but with an interesting twist we’ll get to later.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/use-keyboard-shortcuts&quot;&gt;use-keyboard-shortcuts&lt;/a&gt;: &lt;a href=&quot;https://github.com/SAITS/use-keyboard-shortcuts/blob/433f338b8b3e29edf33c10846097e6836a6b6f10/src/index.tsx#L116-L118&quot;&gt;uses both &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;key&lt;/code&gt;&lt;/a&gt; in a way that makes me think it will break under specific circumstances on alternative layouts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A list is a bit hard to parse, let’s look at it in a table too:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Package&lt;/th&gt;
      &lt;th&gt;Uses &lt;code&gt;which&lt;/code&gt;&lt;/th&gt;
      &lt;th&gt;Uses &lt;code&gt;keyCode&lt;/code&gt;&lt;/th&gt;
      &lt;th&gt;Uses &lt;code&gt;code&lt;/code&gt;&lt;/th&gt;
      &lt;th&gt;Uses &lt;code&gt;key&lt;/code&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;react-hotkeys-hook&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✅ (bad)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;mousetrap&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;hotkeys-js&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;tinykeys&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✅ (good)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;combokeys&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;react-hot-keys&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;react-shortcuts&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;@discourse/itsatrap&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;v-hotkey&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ng-keyboard-shortcuts&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;@ngneat/hotkeys&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;shortcuts&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✅ (bad)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;@sofie-automation/sorensen&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✅ (good?)&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;use-keyboard-shortcuts&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;❌&lt;/td&gt;
      &lt;td&gt;✅ (bad)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Holy cow. I knew it was bad but I had no idea it was &lt;em&gt;this&lt;/em&gt; dire. Now obviously, “most downloaded packages under a keyword” is not necessarily representative of the ecosystem as a whole. &lt;a href=&quot;https://www.npmjs.com/package/lexical&quot;&gt;lexical&lt;/a&gt; for example, which is not primarily a keyboard shortcut library but includes some anyways, &lt;a href=&quot;https://github.com/facebook/lexical/blob/33e36779a335d1f4fcdb9969f59275b7a5629337/packages/lexical/src/LexicalEvents.ts#L1011&quot;&gt;uses &lt;code&gt;key&lt;/code&gt;&lt;/a&gt;. Still, it boggles the mind how bad the popular purpose-built ones tend to be.&lt;/p&gt;
&lt;h2&gt;But Wait There’s More&lt;/h2&gt;
&lt;p&gt;Unfortunately, “just use &lt;code&gt;key&lt;/code&gt;” isn’t all sunshine &amp;amp; roses like I may have led you to believe. There’s a reason library authors might shy away from it, even though it’s been supported in all major browsers for &lt;a href=&quot;https://caniuse.com/keyboardevent-key&quot;&gt;almost 8 years&lt;/a&gt; (or 5, if you include Edge), and choose to use &lt;code&gt;code&lt;/code&gt; or its variants instead: the Shift modifier modifies the value produced by &lt;code&gt;key&lt;/code&gt; 🙀&lt;/p&gt;
&lt;p&gt;Wait, that’s it? Like sure, maybe &lt;a href=&quot;https://archives.miloush.net/michkap/archive/2005/04/04/405174.html&quot;&gt;upper/lowercase doesn’t always round-trip&lt;/a&gt;, and doing &lt;code&gt;Shift+2&lt;/code&gt; will be different from &lt;code&gt;Shift+Meta+2&lt;/code&gt;, and all this might change based on the user locale, and oh no yeah that’s a big problem isn’t it. By using &lt;code&gt;key&lt;/code&gt;, you might be able to support &lt;a href=&quot;https://en.wikipedia.org/wiki/Dvorak_keyboard_layout&quot;&gt;DVORAK&lt;/a&gt; a bit better, but &lt;a href=&quot;https://en.wikipedia.org/wiki/German_keyboard_layout&quot;&gt;German&lt;/a&gt; keyboards will have &lt;code&gt;Shift+2&lt;/code&gt; give you &lt;code&gt;&quot;&lt;/code&gt; instead of &lt;code&gt;@&lt;/code&gt; like you’d get on a US layout. As far as I can tell, only the roman alphabet (A-Z) is safe.&lt;/p&gt;
&lt;h3&gt;Even More Actually&lt;/h3&gt;
&lt;p&gt;The event that sparked this post was honestly something a bit more silly: It’s the fact that, on MacOS, the Option (⌥) key &lt;em&gt;also&lt;/em&gt; modifies keys, even on US QWERTY! &lt;code&gt;Alt+c&lt;/code&gt;? Surely you mean &lt;code&gt;Alt+ç&lt;/code&gt; 🙂. &lt;em&gt;That&lt;/em&gt; is what made me switch my initial prototype to use &lt;code&gt;code&lt;/code&gt; instead of &lt;code&gt;key&lt;/code&gt;, which led me to discover this incosistency, which led me down the rabbithole &amp;amp; out the other side with this big corkboard full of red string.&lt;/p&gt;
&lt;h2&gt;What The Good Libraries Have To Do&lt;/h2&gt;
&lt;p&gt;When searching NPM for “shortcut” libraries sorted by most recently updated, I came across &lt;a href=&quot;https://www.npmjs.com/package/keyboard-i18n&quot;&gt;keyboard-i18n&lt;/a&gt;, which has an interesting solution to this problem: it uses the experimental Keyboard API (only supported on Chrome) to read the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/KeyboardLayoutMap&quot;&gt;KeyboardLayoutMap&lt;/a&gt;, which maps &lt;code&gt;code -&amp;gt; key&lt;/code&gt; with no modifiers. From this, you can build a reverse mapping &lt;code&gt;key -&amp;gt; code&lt;/code&gt;, which lets you specify your keyboard shortcuts using &lt;code&gt;key&lt;/code&gt;, but read them using &lt;code&gt;code&lt;/code&gt;, getting you the best of both worlds! &lt;code&gt;@sofie-automation/sorensen&lt;/code&gt; also uses this approach afaict.&lt;/p&gt;
&lt;p&gt;This is not quite the end of it, however; there are certain keys we might want to bind, like &lt;code&gt;Ctrl+[&lt;/code&gt;, that won’t be present on all layouts. &lt;code&gt;keyboard-i18n&lt;/code&gt; has some useful maps for certain keys like this that will work on international layouts without them, by mapping to non-roman characters in a similar location.&lt;/p&gt;
&lt;p&gt;Unfortunately, this comes with a downside: the Keyboard API is only supported on Chrome. Which maybe isn’t a problem if the rest of your app only supports Chrome! But is still a problem if you want to support Safari&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, or that other browser everyone forgets about (Firefox).&lt;/p&gt;
&lt;h2&gt;What We Cross-Browser Plebians Have To Do&lt;/h2&gt;
&lt;p&gt;So, if we want to support all major browsers, and all major keyboard layouts, our keyboard shortcut definitions must:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Only use roman alphabet characters (A-Z) and arabic numbers (0-9)&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;.toLowerCase()&lt;/code&gt; or &lt;code&gt;.toUpperCase()&lt;/code&gt; to normalize case when checking what character was pressed&lt;/li&gt;
&lt;li&gt;Only allow &lt;code&gt;Shift&lt;/code&gt; as a modifier with alphabet characters&lt;/li&gt;
&lt;li&gt;Never allow &lt;code&gt;Alt&lt;/code&gt; as a modifier&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As far as I can tell, there is no general-purpose shortcut library that gets this right. And maybe it’s the state of web search, but I can’t find anyone talking about this either. &lt;a href=&quot;https://github.com/facebook/lexical/pull/6110&quot;&gt;This &lt;code&gt;lexical&lt;/code&gt; PR&lt;/a&gt; is about the closest I could get. I’ll probably just copy them, enforcing these rules within my own proprietary framework.&lt;/p&gt;
&lt;p&gt;Everything is broken, and everything is fine 🔥&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Safari is especially problematic, because it has a very poor track record of adopting new web features in a timely manner. anyways &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>programming</category><category>Web</category></item><item><title>Rochester Photography</title><link>https://www.hazelduvall.dev/blog/posts/2024-12-07-rochester-photography.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-12-07-rochester-photography.html</guid><description>I announce another new photography page, this time for pictures from Rochester!</description><pubDate>Sat, 07 Dec 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Figured I’d keep my photography-posting “streak” up, if you can call it that :P&lt;/p&gt;
&lt;p&gt;This time I have pictures from a trip I took to Rochester, on my own time, to visit a friend who’s at RIT there. Very fun, got a lot more “personal” pics than I did “artsy” ones. Still, got a few at least! Most happy with the last one, think I have a good thru-line for them as well. Check it out! &lt;a href=&quot;/photography/2024-10-rochester.html&quot;&gt;2024-10: Rochester&lt;/a&gt;&lt;/p&gt;</content:encoded><category>Photography</category></item><item><title>Montreal Photography</title><link>https://www.hazelduvall.dev/blog/posts/2024-12-03-montreal-photography.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-12-03-montreal-photography.html</guid><description>I announce a new photography page! Maybe I should find a way to incorporate that into RSS better? Nahhhh</description><pubDate>Tue, 03 Dec 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow I’ve been slacking on this one!! I have like 2? other albums I need to curate &amp;amp; get up here as well. Hoping to get those out of the way so I can focus all my photography attention on my New York City project (sitll very WIP). Then again I have so many other plates to juggle that idk if I’ll get a proper “2024 NYC” out by the end of this year…&lt;/p&gt;
&lt;p&gt;Oh well! At least we have &lt;a href=&quot;/photography/2024-09-montreal.html&quot;&gt;2024-09: Montreal&lt;/a&gt; to look at in the meantime :) I’m pretty happy with these, had to cut quite a lot of cruft to get them tho. Def leaning into being a Digital Photographer with that approach… good thing I love digital photography!!&lt;/p&gt;</content:encoded><category>Photography</category></item><item><title>Tracking Down a &quot;Heisenbug&quot; in Chrome</title><link>https://www.hazelduvall.dev/blog/posts/2024-11-19-chrome-heisenbug-uncovered.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-11-19-chrome-heisenbug-uncovered.html</guid><description>I recount a long and arduous struggle to figure out a Chrome bug that I finally have a reproduction for</description><pubDate>Tue, 19 Nov 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You know the drill. Go on hiatus because life is busy, catch COVID again even tho I wear a mask, and uncover yet another browser bug while still somewhat sick (getting better tho!).&lt;/p&gt;
&lt;p&gt;The bug I have for you today is very special to me. We’ve been encountering it on-and-off at &lt;a href=&quot;https://ro.am&quot;&gt;Roam&lt;/a&gt; for a while now, since January I think? Customers would report “hey something happened and now my entire screen is shifted up”, and we would say “can we see?”, and they would send screenshots showing sure enough, their entire screen was shifted up. It even happened to me once, though it was less dramatic a shift than some:&lt;/p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;img alt=&quot;the Roam map has shifted up slightly&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1370&quot; src=&quot;/_astro/screenshot-0_Z3CIWb.webp&quot; /&gt;&lt;/p&gt;
&lt;figcaption&gt;Names/pfps redacted for privacy. Note the top of the window being cut off, and the bottom of the map having a misaligned border&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Invariably, the reproduction (“someone sends me a chat message while I have Roam open on my external monitor”, “it happens when my computer wakes up from sleep”) wouldn’t work every time for them, and would never work on our computers, so we’d be stumped, and that would be the end of it. It drove me &lt;em&gt;crazy&lt;/em&gt;. Not having access to a consistent reproduction meant I was up a creek with no way to solve it.&lt;/p&gt;
&lt;p&gt;Once, months later mind you, we got lucky that one customer was willing to screenshare during their bug encounter, and I got to poke around second-hand in devtools. What I found was, uh,&lt;/p&gt;
&lt;h2&gt;The Entire &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; Element Was Shifted Up&lt;/h2&gt;
&lt;p&gt;Well that’s just impossible! Ok well clearly it &lt;em&gt;is&lt;/em&gt; possible, given we’re seeing it live, but our mess of like 10 container divs shouldn’t leave any room for the body to scroll at all. And it’s not the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; that’s scrolling, it’s something else entirely!&lt;/p&gt;
&lt;p&gt;Looking at the situation more, I wasn’t entirely convinced that our mess of 10 container divs always behaved correctly. So I rolled up my sleeves and worked to reduce that number to 3 container divs. Everything worked fine, and to top it off, we got no more reports from them or any other customer about their screen shifting! The end :) What a happy tale about reducing technical debt paying off :)&lt;/p&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;p&gt;Except, that’s not the end. That &lt;em&gt;can’t&lt;/em&gt; be the end. No way did I witness something impossible, that only happens in &lt;strong&gt;extremely specific circumstances&lt;/strong&gt;, only on customer machines, for it to be &lt;em&gt;our&lt;/em&gt; fault. My nose is attuned to the smell of browser bugs, and oh brother does it &lt;strong&gt;stink&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Shifting 2 - Electric Boogaloo&lt;/h2&gt;
&lt;p&gt;There’s a longstanding issue with the drag-n-drop library we use, &lt;a href=&quot;https://www.npmjs.com/package/@hello-pangea/dnd&quot;&gt;&lt;code&gt;@hello-pangea/dnd&lt;/code&gt;&lt;/a&gt;, not working in any Electron window besides the main window. So, my coworker Klas Leino recently put in a herculean amout of effort to switch us over to &lt;a href=&quot;https://www.npmjs.com/package/@dnd-kit/core&quot;&gt;&lt;code&gt;dnd-kit&lt;/code&gt;&lt;/a&gt;. Natually, changing drag-n-drop libraries involves lots of reshuffling of divs, with no guarantee that behavior is unaffected. So we did what we normally do: feature-flag it for internal use only, and test it by dog-fooding our own software daily.&lt;/p&gt;
&lt;p&gt;And it’s a good thing we do this too, because sure enough our bug-testing processes caught a bug: another coworker, Theo Ouzhinski, noticed that whenever he clicked an unread message on his external monitor, his screen would shift up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;HM THAT SOUNDS FAMILIAR&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It was a bit different than before, though. Instead of the entire &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; being shifted, it was just the part inside the floating inbox. And instead of being finicky to trigger, it was very reliable: get a new unread message, click on it, boom. And, the most crucial part of all, &lt;em&gt;it reproduced on my machine&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;the inbox window is shifted up very strangely&quot; loading=&quot;lazy&quot; width=&quot;1142&quot; height=&quot;830&quot; src=&quot;/_astro/screenshot-1_Z1oooVJ.webp&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Debugging Time ^w^&lt;/h3&gt;
&lt;p&gt;The next few hours were a flurry of hypotheses and seeing where it reproduced and where it didn’t. In the end, I was left with some required conditions for the bug to reproduce in our app:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reproduces across platforms (Mac, Windows), on many different types of displays&lt;/li&gt;
&lt;li&gt;Depends on the display; e.x. on my Mac’s built-in display, it won’t trigger, but on an external display plugged into the same Mac, it will.&lt;/li&gt;
&lt;li&gt;Reproduces only in Chrome/Electron, not Safari or Firefox&lt;/li&gt;
&lt;li&gt;Must click an &lt;em&gt;unread&lt;/em&gt; channel; normal navigation is unaffected.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;A CSS Footgun?&lt;/h2&gt;
&lt;p&gt;After more digging &amp;amp; some wild hunches, I found out what was actually going on: there was an outer container with &lt;code&gt;overflow: hidden&lt;/code&gt; and a &lt;code&gt;scrollHeight&lt;/code&gt; greater than its own height. When an unread channel is clicked, we load in the messages, then call &lt;code&gt;element.scrollIntoView()&lt;/code&gt; on the earliest unread (incidentally, this is why it only happened for unread messages; normal navigation didn’t make this call). When that earliest unread is “the latest message”, this can cause all containers with room to scroll to scroll to their bottoms, including the &lt;code&gt;overflow: hidden&lt;/code&gt; one. I did not expect this since the &lt;code&gt;overflow: hidden&lt;/code&gt; container &lt;em&gt;should not have scroll on it&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Initially, I thought it was impossible for &lt;code&gt;overflow: hidden&lt;/code&gt; elements to scroll at all. However, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight&quot;&gt;MDN docs for &lt;code&gt;scrollHeight&lt;/code&gt;&lt;/a&gt; falsify this hypothesis: elements with &lt;code&gt;overflow: hidden&lt;/code&gt; &lt;em&gt;can&lt;/em&gt; have a larger &lt;code&gt;scrollHeight&lt;/code&gt; and &lt;em&gt;are&lt;/em&gt; expected to be able to scroll.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;outer&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;height: 400px; overflow: hidden;&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;inner&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;height: 400px; overflow: hidden;&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;content&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;height: 600px; position: relative;&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;top&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Top&amp;lt;/&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;bottom&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;position: absolute; bottom: 0;&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Bottom&amp;lt;/&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this structure, &lt;code&gt;.inner&lt;/code&gt; will be the one to scroll when we call &lt;code&gt;bottom.scrollIntoView()&lt;/code&gt;. And &lt;code&gt;.outer&lt;/code&gt; will have a &lt;code&gt;scrollHeight&lt;/code&gt; of &lt;code&gt;400&lt;/code&gt;, because &lt;code&gt;.inner&lt;/code&gt; doesn’t overflow it at all.&lt;/p&gt;
&lt;h2&gt;A CSS Bug&lt;/h2&gt;
&lt;p&gt;But apparently, under some Sufficiently Complex CSS Conditions, &lt;code&gt;.outer&lt;/code&gt; &lt;em&gt;does&lt;/em&gt; have a &lt;code&gt;scrollHeight&lt;/code&gt; much greater than &lt;code&gt;.inner&lt;/code&gt;, even when both have &lt;code&gt;overflow: hidden&lt;/code&gt;. Based on reading &lt;a href=&quot;https://drafts.csswg.org/cssom-view/#scrolling-area&quot;&gt;the spec&lt;/a&gt;, &lt;em&gt;that’s a bug&lt;/em&gt;: &lt;code&gt;outer.scrollHeight&lt;/code&gt; should not be larger than the box of its only descendant. With that in mind, I’d like to present my hand-minimized reproduction of these Sufficiently Complext CSS Conditions&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, whose &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; ids I’ll be referencing in the coming explanation:&lt;/p&gt;
&lt;p&gt;
&lt;a href=&quot;https://www.hazelduvall.dev/static/2024-11-19/scrollHeightBug/index.html&quot;&gt;https://www.hazelduvall.dev/static/2024-11-19/scrollHeightBug/index.html&lt;/a&gt;
&lt;/p&gt;
Source code:
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;!&lt;/span&gt;&lt;span&gt;doctype&lt;/span&gt;&lt;span&gt; html&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;head&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;gt;scrollHeight bug&amp;lt;/&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      *&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        box-sizing&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;border-box&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      body&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        min-height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;vh&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        text-rendering&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;optimizespeed&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        margin&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      #root&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        background-color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;white&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;black&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      #outer&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        will-change&lt;/span&gt;&lt;span&gt;: transform;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        overflow&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hidden&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      #inner&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        overflow&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hidden&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      #padding&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        margin&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      #scroll&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;600&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;relative&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        overflow&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      #spacer&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;relative&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1500&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        background-color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;lightblue&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      #pixel&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;fixed&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        width&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        margin&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-1&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        border&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        padding&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        overflow&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;hidden&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      #output&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;fixed&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        bottom&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        right&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;head&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;root&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;outer&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;inner&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;padding&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;scroll&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;              &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;spacer&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                &amp;lt;&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;position: absolute; top: 0&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Top&amp;lt;/&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                &amp;lt;&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;position: absolute; bottom: 0&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Bottom&amp;lt;/&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;              &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;              &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pixel&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;output&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; recalc&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; outer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;outer&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; inner&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;inner&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; output&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;output&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        output.innerHTML &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;outer.scrollHeight=${&lt;/span&gt;&lt;span&gt;outer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;scrollHeight&lt;/span&gt;&lt;span&gt;} outer.clientHeight=${&lt;/span&gt;&lt;span&gt;outer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;clientHeight&lt;/span&gt;&lt;span&gt;}&amp;lt;br&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;inner.scrollHeight=${&lt;/span&gt;&lt;span&gt;inner&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;scrollHeight&lt;/span&gt;&lt;span&gt;} inner.clientHeight=${&lt;/span&gt;&lt;span&gt;inner&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;clientHeight&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        setTimeout&lt;/span&gt;&lt;span&gt;(recalc, &lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      setTimeout&lt;/span&gt;&lt;span&gt;(recalc, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;
&lt;p&gt;If the bug occurs, &lt;code&gt;outer.scrollHeight&lt;/code&gt; will be &lt;code&gt;1502&lt;/code&gt;, not matching any of the other values displayed, which are all &lt;code&gt;602&lt;/code&gt;. Because I read the spec, I am confident in calling this a bug, even though both Chrome and Firefox seem to have the same behavior&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Chrome&lt;/th&gt;&lt;th&gt;Firefox&lt;/th&gt;&lt;th&gt;Safari&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img alt=&quot;repros in Chrome&quot; loading=&quot;lazy&quot; width=&quot;1144&quot; height=&quot;883&quot; src=&quot;/_astro/repro-chrome_ZSnzpX.webp&quot; /&gt;&lt;/td&gt;&lt;td&gt;&lt;img alt=&quot;repros in Firefox&quot; loading=&quot;lazy&quot; width=&quot;2322&quot; height=&quot;1796&quot; src=&quot;/_astro/repro-firefox_xt0hb.webp&quot; /&gt;&lt;/td&gt;&lt;td&gt;&lt;img alt=&quot;doesn&amp;amp;#x27;t repro in Safari&quot; loading=&quot;lazy&quot; width=&quot;2660&quot; height=&quot;1892&quot; src=&quot;/_astro/repro-safari_Bz5LF.webp&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;I am also very confident in calling it a bug because removing the &lt;code&gt;will-change: transform;&lt;/code&gt; property from &lt;code&gt;#outer&lt;/code&gt; causes the bug to go away on both Chrome and Firefox&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. Additionally, on Chrome only, doing any of the following will also cause the bug to go away:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setting &lt;code&gt;left: 1px;&lt;/code&gt; on &lt;code&gt;#pixel&lt;/code&gt; (it already had this as a computed value from the default &lt;code&gt;left: auto;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Removing &lt;code&gt;margin: 1px;&lt;/code&gt; from &lt;code&gt;#padding&lt;/code&gt; (??? in Firefox it doesn’t seem to matter if this div is present)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I highly encourage you to play around with this example in DevTools to get a feel for just how &lt;em&gt;weird&lt;/em&gt; it is. That’s the thing with browser bugs: you thought you were standing atop a rock-solid platform, only to find out it’s made of crumbling sand.&lt;/p&gt;
&lt;h2&gt;Resolution&lt;/h2&gt;
&lt;p&gt;The best fix I’ve found for this bug is to just add &lt;code&gt;top: 0;&lt;/code&gt; to &lt;code&gt;#pixel&lt;/code&gt;. This works on both Chrome and Firefox, I think because setting an explicit &lt;code&gt;top&lt;/code&gt; property moves the &lt;code&gt;#pixel&lt;/code&gt; element firmly inside the container it’s supposed to be in, causing no more weird &lt;code&gt;scrollHeight&lt;/code&gt; calculations to happen. I’ll patch &lt;code&gt;dnd-kit&lt;/code&gt; locally, open a PR upstream, and send some P4 bug reports to Chrome and Firefox that will never get fixed. But hey, maybe I’ll be proven wrong! After all, &lt;a href=&quot;2024-03-23-wow-another-chrome-bug.html&quot;&gt;this other bug I independently found&lt;/a&gt; eventually &lt;a href=&quot;https://issuetracker.google.com/issues/325133349&quot;&gt;got fixed&lt;/a&gt;! In any case, just knowing enough about the bug to fix it w/o waiting for Chrome is a huge weight off my shoulders. Thanks for reading, until next time!&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;One unexpected benefit of making a minimal repro is that the bug no longer depends on what monitor you use, only what browser. Lucky, I guess! &lt;a href=&quot;#user-content-fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All of these screenshots are from my work MacBook, running MacOS 15.1 &amp;amp; the latest versions of every browser. The Chrome and FireFox examples repro on my Windows 11 laptop too. &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;And I know it’s not an interaction with stacking contexts, because replacing that with &lt;code&gt;position: relative; z-index: 0;&lt;/code&gt; or &lt;code&gt;will-change: opacity;&lt;/code&gt; (which will also create stacking contexts) makes the bug go away. Something about the &lt;code&gt;transform&lt;/code&gt; optimization path is making things go awry. &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>programming</category><category>Web</category><category>Chrome</category></item><item><title>I Made A Webring</title><link>https://www.hazelduvall.dev/blog/posts/2024-09-22-i-made-a-webring.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-09-22-i-made-a-webring.html</guid><description>In which I show off a webring that I brainstormed w/ some college friends &amp; wrote in under 3 hours</description><pubDate>Sun, 22 Sep 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, both I and a friend of mine (James) have dove back into making our
blogs better. I don’t have a whole lot of graphical changes to show for mine,
so &lt;a href=&quot;https://gallicch.io/&quot;&gt;his&lt;/a&gt; is &lt;strong&gt;much more impressive&lt;/strong&gt;. When he showed it
off in the Discord we share with the rest of our CMU friends, it garnered a lot
of attention, and one thing led to another, and suddenly the talk about
“wouldn’t it be neat if we were all in a webring together?” turned into me
having a domain name in my cart &amp;amp; plans to write the darn thing from scratch
the next morning.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cmuwebr.ing/&quot;&gt;https://cmuwebr.ing/&lt;/a&gt; is the result. I’m pretty proud of it; took 2:30hr from
“ok let’s bang this thing out” to “website is live &amp;amp; ready to have sites added
to it”. I read some other webring implementations before trying this, but chose
not to use any because it really is too darn simple to &lt;em&gt;not&lt;/em&gt; just write your
own that you fully control, imo. There is a file
&lt;a href=&quot;https://cmuwebr.ing/static/sites.json&quot;&gt;https://cmuwebr.ing/static/sites.json&lt;/a&gt; that the server (written in Python
using &lt;a href=&quot;https://sanic.dev/&quot;&gt;Sanic&lt;/a&gt;) reads, and each site on the ring indexes
into it w/ their ID, and the server takes care of redirecting the prev/next
links. I also plan on writing a Javascript snippet that will parse said JSON &amp;amp;
replace the links on the page so redirects don’t have to go thru my server, but
that’s for later.&lt;/p&gt;
&lt;p&gt;As the founder of the webring, of course I’m already on it! You can see it at
the bottom of every page. I think this is a very good use of the footer space;
I do want to encourage more “low-tech” ways of socializing and discovery on the
internet. RSS feeds, webrings, emails, it’s like I’ve travelled back to the
90s!! Not to be all RETVRN (HTML is &lt;strong&gt;&lt;em&gt;way&lt;/em&gt;&lt;/strong&gt; better than it was back then) but
yeah I enjoy this a lot more.&lt;/p&gt;
&lt;p&gt;If you’re a CMU friend &amp;amp; want to join the webring, view the instructions on
&lt;a href=&quot;https://github.com/hazelduvall/cmuwebr.ing&quot;&gt;GitHub&lt;/a&gt;. Or send me an email! If
you’re not a robot I’m sure you can find where…&lt;/p&gt;</content:encoded><category>Web</category><category>CMU</category></item><item><title>Better Static File Handling</title><link>https://www.hazelduvall.dev/blog/posts/2024-09-21-better-static-file-handling.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-09-21-better-static-file-handling.html</guid><description>In which I recount how I made my website redeploys Slightly Faster by serving images from a dedicated static domain, instead of including them inside my git repository.</description><pubDate>Sat, 21 Sep 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For a while now, I’ve had a &lt;a href=&quot;/photography.html&quot;&gt;photography&lt;/a&gt; page on my blog. When I made it, I wasn’t thinking too hard and just followed along with the Astro Image guide which said “put ur images somewhere in &lt;code&gt;src/&lt;/code&gt; and &lt;code&gt;import&lt;/code&gt; them”. One thing led to another, and I ended up with ~800MiB of data in my git repository. :P&lt;/p&gt;
&lt;p&gt;To be clear, git can handle this much data w/o much stress. GitHub gets a little bit sad on the upload, but hey, at least that only happens once, right? But consider: the GitHub Action to deploy my site needs to download the repo in order to run. So &lt;em&gt;every run&lt;/em&gt;, it was downloading ~800MiB, only to restore what it needed from a cache anyways. It got so bad, this repo download step was &lt;em&gt;half the build time&lt;/em&gt; when caches were warm.&lt;/p&gt;
&lt;p&gt;Needless to say, I can do better. So I did! All large static assets are now served from &lt;code&gt;www.hazelduvall.dev/static&lt;/code&gt;, and I’ve rebased by git history to remove all the large objects. Astro is quite smart; it supports loading images from remote URLs while still putting optimized versions in its cache, w/ TTLs reflecting that returned by the &lt;code&gt;Cache-Control&lt;/code&gt; header.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; this, plus caching &lt;code&gt;node_modules&lt;/code&gt;, will be enough to put me under 30s for full site rebuilds. Which is pretty solid! That’s as far as I can realistically push it w/ Astro, because it does need to rebuild the entire site every time. Thinking about building my own CMS, but that’s a project for another day…&lt;/p&gt;</content:encoded><category>Web</category><category>Astro</category></item><item><title>A Safari aspect-ratio CSS Bug</title><link>https://www.hazelduvall.dev/blog/posts/2024-09-14-safari-css-bug.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-09-14-safari-css-bug.html</guid><description>Now for something definitely completely new and different: a Safari bug! So long, Chrome CSS bugs! /s</description><pubDate>Sat, 14 Sep 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow it’s been a hot minute, huh? I did catch COVID again recently, but that was
only for a week, and really the reason I’ve not been posting is because I feel
broadcasting all my hot takes about how terrible Go is (from more experience
working on a Go service that I’ve had to redo many of the abstractions for)
isn’t really productive. But you know what is productive? That’s right, more CSS
bugs! And this time we have something special: a Safari bug! Sort of surprising
that I haven’t shown off more of these, Safari is a pretty busted browser when
you get right down to it. There’s another bug (related to this one) with an
inconsistent repro that I won’t spoil just yet, so for now here’s just a taste
for how weird it can get:&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Problem Statement&lt;/h2&gt;
&lt;p&gt;Consider the following problem: you have an arbitrarily-sized parent container,
and you want to make a child container with a fixed aspect ratio that fits flush
with the bounds of the parent&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Seems simple enough, no?&lt;/p&gt;
&lt;h2&gt;Solution 1: Simple Boundaries&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.container&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  background-color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;#888&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take1.container&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  display&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;flex&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  align-items&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;center&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.layer1&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  background-color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;--color-orange&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take1&lt;/span&gt;&lt;span&gt; .layer1&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  width&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  max-height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  aspect-ratio&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  display&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;flex&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  justify-content&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;center&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.layer2&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  background-color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;--color-blue&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take1&lt;/span&gt;&lt;span&gt; .layer2&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  aspect-ratio&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;label&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;w1&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Width:&amp;lt;/&lt;/span&gt;&lt;span&gt;label&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;w1&quot;&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;range&quot;&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;120&quot;&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;600&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;200&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;label&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;h1&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Height:&amp;lt;/&lt;/span&gt;&lt;span&gt;label&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;h1&quot;&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;range&quot;&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;120&quot;&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;600&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;200&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;c1&quot;&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;container take1&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;layer1&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;layer2&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; register&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;inputId&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;divId&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;what&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; input&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(inputId);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; div&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(divId);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    div.style[what] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; input.value &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &quot;px&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  set&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  input.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;change&quot;&lt;/span&gt;&lt;span&gt;, set);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;#w1&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;#c1&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;width&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;#h1&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;#c1&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;height&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;Width:Height:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Simple! Play around with the sliders to get a feel for how this works; there’s
an blue box inside an orange box inside a gray parent container. How this works
is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Layer 1 (orange) sets:
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;width: 100%&lt;/code&gt; (be as wide as the parent)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aspect-ratio: 1&lt;/code&gt; (make the implicit &lt;code&gt;height: auto&lt;/code&gt; match the width)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max-height: 100%&lt;/code&gt; (clip &lt;code&gt;height&lt;/code&gt; to that of its parent)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That gives us an orange box that can be at most as tall as it is wide. Then:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Layer 2 (blue) sets:
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;height: 100%&lt;/code&gt; (be as tall as the parent)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aspect-ratio: 1&lt;/code&gt; (make the implicit &lt;code&gt;width: auto&lt;/code&gt; match the height)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because Layer 1 has &lt;code&gt;height &amp;lt;= width&lt;/code&gt;, Layer 2 will be a perfect square, every time!&lt;/p&gt;
&lt;p&gt;…except in Safari&lt;/p&gt;
&lt;h2&gt;Safari’s Problem&lt;/h2&gt;
&lt;p&gt;From what I understand, the problem happens at Layer 1. Instead of doing the
procedure outlined above, it instead seems to do something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Layer 1 (orange) sets:
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;width: 100%&lt;/code&gt; (be as wide as parent)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max-height: 100%&lt;/code&gt; (clip &lt;code&gt;height: auto&lt;/code&gt; to that of parent)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aspect-ratio: 1&lt;/code&gt; (make height match width)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Step 2 doesn’t do anything, because the default &lt;code&gt;height: auto&lt;/code&gt; for a container
is &lt;code&gt;0&lt;/code&gt;. It works if you swap around the width/height constraints between the two
layers, (because &lt;code&gt;width: auto&lt;/code&gt; is &lt;code&gt;100%&lt;/code&gt; so does get clipped properly), but this
feels like a hack, and besides there’s a different solution that only uses one
layer.&lt;/p&gt;
&lt;h2&gt;Solution 2: Good ol’ &lt;code&gt;margin: auto&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take2.container&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;relative&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take2&lt;/span&gt;&lt;span&gt; .layer1&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;absolute&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  inset&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  margin&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;auto&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  max-height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  aspect-ratio&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;label&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;w2&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Width:&amp;lt;/&lt;/span&gt;&lt;span&gt;label&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;w2&quot;&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;range&quot;&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;120&quot;&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;600&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;200&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;label&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;h2&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;Height:&amp;lt;/&lt;/span&gt;&lt;span&gt;label&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;h2&quot;&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;range&quot;&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;120&quot;&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;600&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;200&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;c2&quot;&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;container take2&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;layer1&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;#w2&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;#c2&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;width&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;#h2&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;#c2&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;height&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;Width:Height:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To me, it’s a bit more magical how this works. This is what I &lt;em&gt;think&lt;/em&gt; is happening:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;position: absolute; inset: 0&lt;/code&gt; inside a &lt;code&gt;position: relative&lt;/code&gt; sets the child
container’s width and height to be that of the parent
&lt;ul&gt;
&lt;li&gt;but not the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; properties directly! those are both still
&lt;code&gt;auto&lt;/code&gt; so it can participate in &lt;code&gt;aspect-ratio&lt;/code&gt; resolution.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aspect-ratio: 1&lt;/code&gt; is applied, defaulting to setting height based on width&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max-height: 100%&lt;/code&gt; is applied, clipping height&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aspect-ratio: 1&lt;/code&gt; is applied again, this time setting width based on height,
because width is still &lt;code&gt;auto&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This explanation checks out with all my previous ones: some sort of
“&lt;code&gt;auto&lt;/code&gt;-resolution loop” happens, and we never saw it because earlier, one of
the &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt; was non-&lt;code&gt;auto&lt;/code&gt;. It also now makes sense why this works in
all browsers, because the order of &lt;code&gt;aspect-ratio&lt;/code&gt;/&lt;code&gt;max-height&lt;/code&gt; no longer
matters; &lt;code&gt;aspect-ratio&lt;/code&gt; gets applied twice anyways.&lt;/p&gt;
&lt;p&gt;What &lt;code&gt;margin: auto&lt;/code&gt; does then, is center the div in both axes (and in Safari’s
case, make it so the vertical margin can no longer be negative, because of
course Safari is still special). You can pin the container to a given side by
setting &lt;code&gt;margin-&amp;lt;side&amp;gt;: 0&lt;/code&gt; afterwards.&lt;/p&gt;
&lt;p&gt;Phew!! Box sizing is hard, man.&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;There’s an even harder variant of this problem that I had for
&lt;a href=&quot;https://ro.am/howard/&quot;&gt;https://ro.am/howard/&lt;/a&gt;: you have an arbitrary-sized
parent container, and you want the child to overflow the parent in only one
dimension with a fixed aspect ratio, but not just use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit&quot;&gt;&lt;code&gt;object-fit: cover&lt;/code&gt;&lt;/a&gt; on an image
because there are elements that need to be positioned relative to that image. I
won’t go into it here, you can read that page’s source if you’d like tho :) &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>programming</category><category>Web</category><category>Safari</category></item><item><title>A Third Browser Bug...</title><link>https://www.hazelduvall.dev/blog/posts/2024-07-12-a-third-browser-bug.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-07-12-a-third-browser-bug.html</guid><description>I found yet another weird edgecase in some JavaScript + CSS APIs when doing something for a work project. Great. At least this time it&apos;s not just Chrome, but all browsers that are buggy though??</description><pubDate>Fri, 12 Jul 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So at work, I had the opportunity to write a small tool that dumps the current state of the &lt;code&gt;document&lt;/code&gt; into a single static HTML file, making no network requests. For the most part, it turned out to be a lot simpler than I expected! DOM APIs are really good nowadays (all hail &lt;code&gt;querySelectorAll&lt;/code&gt;). It should have taken me like 3 hours tops, from starting up the editor to pushing the PR, but instead it took all day, because of one very weird bug.&lt;/p&gt;
&lt;h2&gt;Virtual StyleSheets&lt;/h2&gt;
&lt;p&gt;One thing I learned poking around in our app for a bit is that, not all &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; elements have to be present in the document! That’s right, you can define CSS rules &lt;em&gt;entirely in JavaScript&lt;/em&gt;, never having their state show up in the DOM at all. You do this thru the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet&quot;&gt;&lt;code&gt;CSSStyleSheet&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets&quot;&gt;&lt;code&gt;document.adoptedStyleSheets&lt;/code&gt;&lt;/a&gt; APIs, supported on all major browsers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; styleSheet&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; CSSStyleSheet&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;styleSheet.&lt;/span&gt;&lt;span&gt;insertRule&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;* { color: red !important; }&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;document.adoptedStyleSheets.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(styleSheet);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example code will turn all text on the page red. Try it out in your browser console now!!&lt;/p&gt;
&lt;p&gt;In any case, I knew about this restriction beforehand, and was prepared. The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/styleSheets&quot;&gt;&lt;code&gt;document.styleSheets&lt;/code&gt;&lt;/a&gt; objects can also be modified in-place, so really the only way to properly dump everything was to run something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// Create a new empty document:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// &amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;style&amp;gt;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; outputDocument&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Document&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; html&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; outputDocument.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;html&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;outputDocument.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(html);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; head&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; outputDocument.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;head&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;html.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(head);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; outputDocument.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;style&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;head.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(style);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// Add all rules to the style element&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; rules&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;document.styleSheets, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;document.adoptedStyleSheets].&lt;/span&gt;&lt;span&gt;flatMap&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  (&lt;/span&gt;&lt;span&gt;styleSheet&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;styleSheet.cssRules].&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;cssRule&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; cssRule.cssText),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;style.sheet.&lt;/span&gt;&lt;span&gt;replaceSync&lt;/span&gt;&lt;span&gt;(rules.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Virtual Documents&lt;/h2&gt;
&lt;p&gt;As it turns out, this doesn’t work! Why?? As it turns out, browsers are very finicky about element state; many properties are defined only when they are actively being rendered, which this virtually-created &lt;code&gt;Document&lt;/code&gt; is not. This extends for everything created in the “context”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; of that virtual &lt;code&gt;Document&lt;/code&gt; too, so &lt;code&gt;style.sheet&lt;/code&gt; will be undefined in the above example.&lt;/p&gt;
&lt;p&gt;No problem, though! Instead of modifying thru &lt;code&gt;style.sheet.replaceSync&lt;/code&gt;, we can do what MDN recommends on another page somewhere else, and use &lt;code&gt;innerHTML&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;style.innerHTML &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; rules.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and boom, everything is working! Except wait a minute, certain styles got applied right, but other styles are wonky. Diffing between the two, we see that no direct child selectors (that is, ones like &lt;code&gt;.a &amp;gt; .b&lt;/code&gt;) are working. And looking in the rendered source, we find the culprit: they’re being written as &lt;code&gt;.a &amp;amp;gt; .b&lt;/code&gt;. Huh??&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;innerHTML&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Some background on &lt;code&gt;innerHTML&lt;/code&gt;: it has some simple character escapes built-in, from some sort of “fragment parsing algorithm” that detects if something should be text or should be an HTML element. This makes code like this “just work”:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; test&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;doc&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;elemType&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; elem&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; doc.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(elemType);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  elem.innerHTML &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; text;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(elem.innerHTML);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;(document, &lt;/span&gt;&lt;span&gt;&quot;p&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;2 + 2 &amp;lt; 5&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// prints &quot;2 + 2 &amp;amp;lt; 5&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, because CSS wants &lt;em&gt;unescaped&lt;/em&gt; symbols, the usual escaping rules seemingly do not apply to it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;(document, &lt;/span&gt;&lt;span&gt;&quot;style&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;p &amp;gt; h2 { color: blue; }&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// prints &quot;p &amp;gt; h2 { color: blue; }&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;…except, of course, when you have a &lt;strong&gt;virtual &lt;code&gt;Document&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; Document&lt;/span&gt;&lt;span&gt;(), &lt;/span&gt;&lt;span&gt;&quot;style&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;p &amp;gt; h2 { color: blue; }&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// prints &quot;p &amp;amp;gt; h2 { color: blue; }&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because of course! Why &lt;em&gt;would&lt;/em&gt; that work? Clearly I am extremely silly for expecting otherwise.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I spent a lot of time spinning my wheels on this one, probably because I had skipped lunch 2 hours ago by the time I got to this point. Having a lunch and coming back, the solution was easy: just do&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; output&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; `&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;style&amp;gt;${&lt;/span&gt;&lt;span&gt;rules&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;${&lt;/span&gt;&lt;span&gt;document&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;outerHTML&lt;/span&gt;&lt;span&gt;}&amp;lt;/html&amp;gt;`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I didn’t need to keep everything as elements in the first place! All I cared about was the output text. A bit more magic to remove all scripts and make all images load from data URLs&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, and bam it was working flawlessly. In the end I still had a lot of fun with this, hope you learned something too!&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I’m probably misusing this term here. Oh well you get the point! &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Secret ;) &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>programming</category><category>Web</category></item><item><title>More Photography!</title><link>https://www.hazelduvall.dev/blog/posts/2024-06-11-more-photography.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-06-11-more-photography.html</guid><description>In which I reveal I have not one, but two whole new sets of photos available for display now, on this very website.</description><pubDate>Tue, 11 Jun 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I haven’t been active on this blog much, but I &lt;em&gt;have&lt;/em&gt; been very active at work! One consequence of that is I’ve gone on a few work trips, and the inspiration from those trips compelled me to start taking artsy photos again, so here I am! My &lt;a href=&quot;/photography.html&quot;&gt;photography page&lt;/a&gt; has been updated with these trips, to &lt;a href=&quot;/photography/2024-05-chicago.html&quot;&gt;Chicago&lt;/a&gt; and &lt;a href=&quot;/photography/2024-06-london.html&quot;&gt;London&lt;/a&gt; respectively. I’m fairly proud of myself for getting back into it at all, and with a borrowed camera from my dad (thanks, Dad!) I can hopefully keep this hobby up even longer.&lt;/p&gt;
&lt;p&gt;In other neat news, I have started to learn Japanese! I’ve memorized the basic hiragana and katakana alphabets and am starting to learn Kanji thru &lt;a href=&quot;https://www.wanikani.com/&quot;&gt;WaniKani&lt;/a&gt;. It’s pretty slow going, but that is how I learn best I think, thru routine-building. Still very early so we’ll see how this goes.&lt;/p&gt;
&lt;p&gt;In less good news, I have contracted COVID-19 for a second time :(((( This time around was &lt;em&gt;hopefully&lt;/em&gt; not from any family members (that would be bad!) but from some other transit/event. Still recovering, but honestly working on this blog is low-effort enough and I am bored &amp;amp; needed something to do so this is good :P&lt;/p&gt;
&lt;p&gt;That’s all for now, hopefully I will have another update before 3 months have passed again!&lt;/p&gt;</content:encoded><category>Photography</category></item><item><title>You Won&apos;t Believe That I Found Another Chrome Rendering Bug</title><link>https://www.hazelduvall.dev/blog/posts/2024-03-23-wow-another-chrome-bug.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-03-23-wow-another-chrome-bug.html</guid><description>Another foray into debugging a Chrome rendering bug, this time with extra platform-specific goodness!</description><pubDate>Sat, 23 Mar 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;EDIT: As of 2024-10-15, when Chrome 130 was released, this bug is now &lt;a href=&quot;https://issuetracker.google.com/issues/325133349&quot;&gt;fixed&lt;/a&gt;! Yahoo!!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;So in one of my &lt;a href=&quot;2023-12-28-i-think-i-found-a-webkit-bug.html&quot;&gt;previous posts&lt;/a&gt;,
I outlined how Chrome had a rendering bug where it did not properly mask
anti-aliasing pixels under certain complex CSS &lt;code&gt;mask&lt;/code&gt; conditions. And wouldn’t
you know it, right as I publish an &lt;a href=&quot;2024-03-15-working-around-a-webkit-bug.html&quot;&gt;update&lt;/a&gt;
to that post, I find yet &lt;em&gt;another&lt;/em&gt; Chrome rendering bug at work.&lt;/p&gt;
&lt;p&gt;This story starts a couple months ago, when I’m working on a refresh of some of
the colors and layout of our app’s main page to match a new design. The designer
comes up to me and says “ayo check out this weird bug I’m having”, and shows me.&lt;/p&gt;
&lt;p&gt;On their screen, many of the colors look darker than normal. And suddenly, when they
hovers over a specific UI element, all the colors snap back to normal. As soon
as they stops hovering, the colors go back to being weird again. I have never seen
this happen before.&lt;/p&gt;
&lt;p&gt;I take a look at their browser state in devtools, and discover something
distrubing: all the CSS is correct. Everything is &lt;em&gt;exactly&lt;/em&gt; the same as on my
machine, and yet the results are different. I’ve done nothing wrong except fail
to understand what the heck is going on here.&lt;/p&gt;
&lt;h2&gt;Narrowing Down A Culprit&lt;/h2&gt;
&lt;p&gt;As for “why do the colors snap back to normal when a div is hovered?”, that part
had a simple yet outlandish explanation: hovering a certain div creates a
&lt;code&gt;blur&lt;/code&gt; effect, the addition of which must’ve done something to the way the rest
of the page was rendered. As for “why are the colors wrong in the first place?”,
that part was harder to figure out.&lt;/p&gt;
&lt;p&gt;I had put it on the deep backlog at the time, because “shipping the thing” was
more important than “solving a bug that seems to hardly ever occur in practice”.
But just recently, enough people independently had the bug that we finally had
some leads.&lt;/p&gt;
&lt;p&gt;One of my coworkers noticed this bug only occured for them when another specific
coworker was signed in with their test account. Wait, What? They also noticed
that, when the test account’s profile picture showed up on screen, their display
backlight lit up more, which usually occurs when trying to display an HDR image.&lt;/p&gt;
&lt;p&gt;Excited for a reproduction, I lauched the app on my own machine. The bug didn’t
reproduce. Then, I recalled that the monitor I usually test on might not be
HDR-compatible, so I dragged it to another monitor that was: my Macbook’s
built-in screen. And lo and behold, I had a reproduction. I opened up devtools,
unloaded the image thought to be the culprit, and sure enough, the bug went
away.&lt;/p&gt;
&lt;p&gt;So! Something about HDR images, and whatever &lt;code&gt;div&lt;/code&gt; setup we have going on is
causing trouble.&lt;/p&gt;
&lt;h2&gt;Why Is That??&lt;/h2&gt;
&lt;p&gt;To answer this question completely, I would have to dive into Chromium
internals. Unfortunately, I am not that good at diving into Chromium internals,
so instead I just found a couple bug reports that might give some insight:&lt;/p&gt;
&lt;h3&gt;HDR Was A Known Problem&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://issues.chromium.org/issues/40114989&quot;&gt;This bug&lt;/a&gt; was the first relevant
result when I searched for something along the lines of “blur interacts weirdly
with HDR MacOS Chrome??”. Back in Chrome M80, they had to disable HDR support
for MacOS because they “fall out of HDR mode if there are extra render passes”,
like blur, “which looks bad.”&lt;/p&gt;
&lt;p&gt;Despite the age of this bug, this is almost the exact result I was seeing!
Adding a &lt;code&gt;blur&lt;/code&gt; anywhere did cause other stuff to fall out of a (presumably bad)
HDR mode. And because the fix for this bug was to just disable HDR, it could be
likely the underlying issue was never addressed fully. Feeling confident I was
on the right track, I kept looking…&lt;/p&gt;
&lt;h3&gt;HDR Still Is A Problem&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://issuetracker.google.com/issues/325133349&quot;&gt;This next bug&lt;/a&gt; is much closer
to what I was seeing: an HDR image causing a background with opacity to render
incorrectly! The reproduction isn’t exactly the same as what we have going on in
our app, but hey, close enough.&lt;/p&gt;
&lt;p&gt;Below, I’ve demonstrated the reproduction from the bug report: an HDR image with
&lt;code&gt;position: absolute&lt;/code&gt; outside a parent div with an opacity less than 1:&lt;/p&gt;

&lt;p&gt;
&lt;/p&gt;&lt;div&gt;
  
  &lt;div&gt;
    &lt;img src=&quot;https://www.hazelduvall.dev/static/2024-03-20/dog.jpg&quot; /&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;If you’re in most browsers, you should only see the border color of the square
change when the checkbox is checked. If, however, your are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;using Chrome&lt;/li&gt;
&lt;li&gt;on MacOS&lt;/li&gt;
&lt;li&gt;on an XDR-enabled display&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then the above demonstration should make it so that checking the checkbox also
changes the background color of the lower square. This should never happen,
because the square is simply &lt;code&gt;background-color: white; opacity: 0.5;&lt;/code&gt; over an
already-white background, so it should be white always (like in most browsers).
The reason the background color changes is because the checkbox has a
&lt;code&gt;backdrop-filter: blur&lt;/code&gt; property only when it is checked, and as mentioned
previously, enabling this blur disables the buggy HDR.&lt;/p&gt;
&lt;p&gt;If you don’t believe me, observe this screen recording I took of the bug. Yes,
it does show up in screen capture (thank goodness), so it’s definitely not a
display bug of any sort:&lt;/p&gt;
&lt;figure&gt;

&lt;figcaption&gt;Video showing a recreation of the bug&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note that this bug is &lt;em&gt;extremely&lt;/em&gt; sensitive to the types of stacking contexts
that can be used to trigger it. You can have roughly the same layout with any of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;changing which &lt;code&gt;div&lt;/code&gt; has the &lt;code&gt;position: relative&lt;/code&gt; on it&lt;/li&gt;
&lt;li&gt;positioning image based on &lt;code&gt;left&lt;/code&gt; instead of &lt;code&gt;right&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;image overlapping div&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and the bug &lt;em&gt;will not trigger&lt;/em&gt;. This is why I wasn’t able to make a minimal
reproduction of what’s actually happening in our app. In our app, the
image can (1) be at &lt;code&gt;opacity: 1&lt;/code&gt;, (2) overlapping the &lt;code&gt;div&lt;/code&gt;, and (3) all
transparent colors everywhere are affected, which is even wilder. Shame I wasn’t
able to show it off…&lt;/p&gt;
&lt;p&gt;Anyways, now I am fairly certain it is a Chrome bug. However, because I do not
have the chops to write a patch that fixes it at the source, I have to work
around it just using CSS.&lt;/p&gt;
&lt;h2&gt;Take 1&lt;/h2&gt;
&lt;p&gt;My thinking:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If adding some &lt;code&gt;blur&lt;/code&gt; anywhere stops whatever’s going on with the
transparency, then just having a random 1x1 div in the corner of the screen
should do the trick!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sure enough, that did it! No more weird transparency rendering issues,
everything looks normal again, we’re all happy yaaaaaaay :)&lt;/p&gt;
&lt;p&gt;yeah. um. Remember the first bug? Turns out this trick &lt;em&gt;disables HDR entirely&lt;/em&gt;,
which is not a good thing if your CEO likes to view HDR videos in his app and
can tell the difference.&lt;/p&gt;
&lt;h2&gt;Take 2&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The problem is a combination of HDR, Weird Stacking Contexts, and Transparent
Colors. The easiest one of these to fix is Transparent Colors, so if I make the
offending background colors Not Transparent, everything will be fine!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yep! Turns out it’s not too hard to hack together something with
&lt;a href=&quot;https://colorjs.io&quot;&gt;Color.js&lt;/a&gt; that roughly emulates what the transparent
blending would otherwise do. I got it so that even in a side-by-side comparison,
I could hardly tell the difference.&lt;/p&gt;
&lt;p&gt;And that’s that!! I’ve worked around yet another Chrome bug purely by contoring
the CSS into the correct shape, which is why I’m a Software Engineer :)&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This bug was really hard to find because it only happened under very specific
conditions, and the outcome seemed simply impossible. Blur on one element
affecting all elements on the page? Chrome drawing transparent colors
incorrectly?? Surely you must be joking, Mr. Feynman. Nope, turns out Chrome has
rendering bugs, and stumbling across them is more likely than I thought.&lt;/p&gt;
&lt;p&gt;Anyways, hope this was somewhat educational, see y’all next time!&lt;/p&gt;</content:encoded><category>programming</category><category>Web</category><category>Chrome</category></item><item><title>RSS Feed Is Live</title><link>https://www.hazelduvall.dev/blog/posts/2024-03-16-rss-feed-live.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-03-16-rss-feed-live.html</guid><description>I announce that my blog now has an RSS Feed! Again. After the one that came with Hakyll was removed and I had to add back in one for Astro.</description><pubDate>Sat, 16 Mar 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My blog now has an &lt;a href=&quot;/blog/rss.xml&quot;&gt;RSS Feed&lt;/a&gt;!. Again. After the one that came with Hakyll got removed in &lt;a href=&quot;2023-10-22-new-blog-framework.html&quot;&gt;the upgrade to Astro&lt;/a&gt;, and I had to update to &lt;a href=&quot;https://docs.astro.build/en/guides/rss/&quot;&gt;@astrojs/rss&lt;/a&gt;. I also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ditched my old janky globbing setup and switched to using &lt;a href=&quot;https://docs.astro.build/en/tutorials/add-content-collections/&quot;&gt;Astro content collections&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;minimized my CSS massively (by hand! wordpress theme was bloated for what I’m doing with it)&lt;/li&gt;
&lt;li&gt;removed all custom fonts (it’s using your system &lt;code&gt;serif&lt;/code&gt; and &lt;code&gt;monospace&lt;/code&gt; fonts now)&lt;/li&gt;
&lt;li&gt;fixed the caching in Github Actions so now it won’t have to regenerate all my images every time I push.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in all, very productive blog work! but boy is it late at night now whoops.&lt;/p&gt;</content:encoded><category>Web</category><category>RSS</category><category>Astro</category></item><item><title>Working Around A Chrome Bug (And Other CSS Limitations)</title><link>https://www.hazelduvall.dev/blog/posts/2024-03-15-working-around-a-webkit-bug.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2024-03-15-working-around-a-webkit-bug.html</guid><description>Solving my earlier problem by (ab)using inline SVG images to create masks, instead of CSS-native geometry</description><pubDate>Fri, 15 Mar 2024 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In my &lt;a href=&quot;2023-12-28-i-think-i-found-a-webkit-bug.html&quot;&gt;previous post&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, I covered how Chrome’s &lt;code&gt;mask-image&lt;/code&gt; support doesn’t do any antialiasing for &lt;code&gt;radial-gradient&lt;/code&gt;, and what that meant for making notification badge cutouts. In this post, I’ll go over a different way of providing a &lt;code&gt;mask-image&lt;/code&gt; that &lt;em&gt;does&lt;/em&gt; have antialiasing (in all browsers!), namely SVGs.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Recall that we left off with a mask that looked something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take3&lt;/span&gt;&lt;span&gt; .pfp&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border-radius&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    radial-gradient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      ellipse&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; at&lt;/span&gt;&lt;span&gt; 80&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      transparent&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      white&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    linear-gradient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      to&lt;/span&gt;&lt;span&gt; bottom&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      white&lt;/span&gt;&lt;span&gt; 40&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      transparent&lt;/span&gt;&lt;span&gt; 40&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    linear-gradient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      to&lt;/span&gt;&lt;span&gt; left&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      transparent&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      white&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-composite&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;subtract&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;horiz&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take3&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/randomlogo.png&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take3&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That is, one that was a little chunky on the curved parts. This got me wondering: is it possible to do better?&lt;/p&gt;
&lt;p&gt;As it turns out, yes!! Using an svg instead of a CSS geometry object works a lot better. In the work codebase, I wrote a fancy SVG generator that embeds things directly inline with &lt;code&gt;url(&apos;data:image/svg+xml;utf8,${svg}&apos;)&lt;/code&gt;, because we already use a lot of templated CSS generated by JS, but for this demonstration I’ll just be using regular urls:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take4&lt;/span&gt;&lt;span&gt; .pfp&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border-radius&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;/2024-03-15/mask1.svg&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* This is used because it&apos;s a lot easier to generate complex SVGs that are black and white, instead of transparent and not transparent */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-mode&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;luminance&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; 
&lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Great!! Now, let’s just slap our notification badge back on and… voilà!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.badge&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  font-variant-numeric&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;tabular-nums&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border-radius&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;14&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  background-color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;--color-orange&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  font-size&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  line-height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;absolute&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  top&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  left&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;66&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  padding&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;horiz&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take4&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/randomlogo.png&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;100&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take4&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;9001&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;div&gt;100&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;9001&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, for the sake of the argument, just like last time, let’s consider what happens if you want More Badges. And also, you want to have this be composable, so you can nest them. Well, then this happens:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take5&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;/2024-03-15/mask2.svg&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-mode&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;luminance&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.badge-lower&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;absolute&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  background-color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;--color-green&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  width&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;28&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;28&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  bottom&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  right&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border-radius&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;horiz&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take4&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;take5&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/randomlogo.png&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;100&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge-lower&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take4&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;take5&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;9001&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge-lower&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;div&gt;100&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;9001&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Gah!! Suddenly, all the talk about &lt;code&gt;no-clip&lt;/code&gt; and &lt;code&gt;no-repeat&lt;/code&gt; from the last post comes rushing back. This is no longer any sort of Chrome bug I don’t think, but rather just a way the CSS &lt;code&gt;mask&lt;/code&gt; property is specified to behave.&lt;/p&gt;
&lt;p&gt;Reading the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/mask&quot;&gt;&lt;code&gt;mask&lt;/code&gt; specification&lt;/a&gt; more thoughroughly, we begin to see a solution:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;no-repeat&lt;/code&gt; and &lt;code&gt;no-clip&lt;/code&gt; (obviously)&lt;/li&gt;
&lt;li&gt;Explicitly set the &lt;code&gt;mask-position&lt;/code&gt; and &lt;code&gt;mask-size&lt;/code&gt; so it will only cover the part of the image we want&lt;/li&gt;
&lt;li&gt;Combine it with another mask that does cover the whole image, using &lt;code&gt;mask-composite: exclude&lt;/code&gt; to cut away at that mask.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Doing that, we come up with the following solution:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take6&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* We&apos;re actually going to cut away at the lower mask, and need to use an inverted image */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* mask-image: */&lt;/span&gt;&lt;span&gt; url&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;/2024-03-15/mask2-inverse.svg&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* mask-mode: */&lt;/span&gt;&lt;span&gt; luminance&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* mask-composite: */&lt;/span&gt;&lt;span&gt; exclude&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* These make it so we only mask the one part */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* mask-repeat: */&lt;/span&gt;&lt;span&gt; no-repeat&lt;/span&gt;&lt;span&gt; /* mask-clip: */&lt;/span&gt;&lt;span&gt; no-clip&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* position the mask and size it appropriately */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* mask-position: */&lt;/span&gt;&lt;span&gt; bottom&lt;/span&gt;&lt;span&gt; left&lt;/span&gt;&lt;span&gt; / &lt;/span&gt;&lt;span&gt;/* mask-size: */&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* And finally, the mask that covers the whole image */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    linear-gradient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;white&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;white&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;no-clip&lt;/span&gt;&lt;span&gt; luminance&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;horiz&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take4&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;take6&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/randomlogo.png&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;100&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge-lower&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take4&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;take6&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;9001&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;badge-lower&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;div&gt;100&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;9001&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And there you have it! Perfectly anti-aliased, composable masks for all your CSS masking needs.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I swear we’re the only application I’ve seen that actually does something like this. Everywhere else I’ve looked either doesn’t use a mask at all, or just sets a &lt;code&gt;border&lt;/code&gt; color to fake a mask.&lt;/p&gt;
&lt;p&gt;This is why I put in the work tho, to prove we’re better than that. CSS allows us to do these things, so do them we shall!!&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;oh no it’s been very too long since that last post. I meant to get this out sooner but have been procrastinating with other projects in the meantime… figured that, while I was doing other work for my blog, I should at least write an article :P &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>programming</category><category>Web</category><category>Chrome</category></item><item><title>My Blog Has More CI Now</title><link>https://www.hazelduvall.dev/blog/posts/2023-12-29-my-blog-has-more-ci-now.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-12-29-my-blog-has-more-ci-now.html</guid><description>A quick update on what I&apos;ve done with my blog&apos;s Continuous Integration system, and why I think it&apos;s pretty cool</description><pubDate>Fri, 29 Dec 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At work, I’ve seen my coworker set up this new cool tool called
&lt;a href=&quot;https://www.mend.io/renovate/&quot;&gt;Rennovate&lt;/a&gt; which automatically scans your
repository and opens PRs for updating dependencies. You control it through an
&lt;a href=&quot;https://developer.mend.io/github/hazelduvall/blog&quot;&gt;online dashboard&lt;/a&gt;, or, and this
is the part I found really cool, through the &lt;a href=&quot;https://github.com/hazelduvall/blog/issues/4&quot;&gt;Github UI
itself&lt;/a&gt; via (presumably) some fun
webhook hacks.&lt;/p&gt;
&lt;p&gt;However, for this system to work properly, there needs to be some way of knowing if an opened PR is good to merge or not. I don’t &lt;em&gt;really&lt;/em&gt; want to do the manual work of “check out an automatically opened PR” &lt;span&gt;&lt;span&gt;→\rightarrow&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; “make sure it works locally” &lt;span&gt;&lt;span&gt;→\rightarrow&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; “merge the PR and clean up local git” when I could have computers do that work for me! So I did a bunch of work to make computers do that work for me :]&lt;/p&gt;
&lt;p&gt;I borrowed heavily from the canonical Astro usecase, &lt;a href=&quot;https://github.com/withastro/docs/blob/main/.github/workflows/ci.yml&quot;&gt;their own documentation site&lt;/a&gt;, which seems to have been a pretty good template. Lots of “fun” making typescript and eslint and prettier all play nice together, but yep now it works now!! It correctly failed on the &lt;a href=&quot;https://github.com/hazelduvall/blog/pull/12&quot;&gt;major version update&lt;/a&gt; of Astro, which I’ll need to do manually at some point, but that’s for another time yes.&lt;/p&gt;</content:encoded><category>Web</category><category>Astro</category></item><item><title>I Think I Found A Chrome Bug</title><link>https://www.hazelduvall.dev/blog/posts/2023-12-28-i-think-i-found-a-webkit-bug.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-12-28-i-think-i-found-a-webkit-bug.html</guid><description>In which I go over how different values of `mask` can behave differently, despite intending for them to do the same thing. Shows off some of what I&apos;ve learned in my job doing web development</description><pubDate>Thu, 28 Dec 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At work, I’m in between a few big projects, spending my time polishing the UI so it shines. One of those polish items has been to revamp how we do notification badges, and through that, I think I discovered a WebKit bug EDIT: Chrome bug. Upon further testing, this bug does not appear to be in Safari, despite also appearing in Firefox? idk man it’s just weird&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;The simplest way to do a notification badge is like this:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Nice ‘n easy! Just slap a &lt;code&gt;position: absolute&lt;/code&gt; inside a &lt;code&gt;position: relative&lt;/code&gt;
and everything’s pretty much good-to-go. The only downside to this is that is
doesn’t &lt;em&gt;quite&lt;/em&gt; look professional enough. A neat little detail to have is a
little transparent space between the profile picture and the thing going on top
of it, like in Discord.&lt;/p&gt;
&lt;p&gt;Now, you &lt;em&gt;can&lt;/em&gt; just fake this effect by slapping on a &lt;code&gt;border: 5px solid var(--background-color)&lt;/code&gt; onto the the thing, but if the background color ever
changes you have to animate this &lt;code&gt;border&lt;/code&gt; property with the same curves, so for
separation of concerns it’s just easier&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; to have the image be truly
transparent in that area.&lt;/p&gt;
&lt;p&gt;So! Let’s try to do exactly that. A quick dive into what exists out there in
general brings up the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/mask&quot;&gt;mask&lt;/a&gt; property, with a
specially crafted
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/radial-gradient&quot;&gt;radial-gradient&lt;/a&gt;
as the mask source. Let’s see how this looks, first without the indicator:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;/* irrelevant properties omitted for brevity */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take1&lt;/span&gt;&lt;span&gt; .pfp&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border-radius&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;radial-gradient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ellipse&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; at&lt;/span&gt;&lt;span&gt; 85&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 85&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    transparent&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    white&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;horiz&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take1&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/randomlogo.png&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take1&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Interesting!! What this is doing, effectively, is drawing a completely
transparent circle at a specified location within the bounding box, using a
&lt;code&gt;transparent 99%&lt;/code&gt; and &lt;code&gt;white 100%&lt;/code&gt; stop to effectively get a hard line instead
of a gradient.&lt;/p&gt;
&lt;p&gt;Unfortunately, this approach is not without problems.&lt;/p&gt;
&lt;h2&gt;Problem 1: It Looks Chunky&lt;/h2&gt;
&lt;p&gt;This becomes more apparent when we try to add the dot:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.indicator&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  aspect-ratio&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border-radius&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take1&lt;/span&gt;&lt;span&gt; .indicator&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  width&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;absolute&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  bottom&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-3.5&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  right&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-3.5&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;horiz&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take1&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/randomlogo.png&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator green&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take1&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator green&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, we can more clearly see that the masked-out part is &lt;strong&gt;&lt;em&gt;not anti-aliased&lt;/em&gt;&lt;/strong&gt;, unlike the circular borders of the profile picture and indicator. This is part of the bug I’m referring to in the post title.&lt;/p&gt;
&lt;h2&gt;Problem 2: It Clips&lt;/h2&gt;
&lt;p&gt;Things get worse if we try to add a second indicator (and not just from a
design perspective, lol).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take2&lt;/span&gt;&lt;span&gt; .pfp&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;radial-gradient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ellipse&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; at&lt;/span&gt;&lt;span&gt; 85&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 85&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    transparent&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    white&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  background-color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;initial&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take2&lt;/span&gt;&lt;span&gt; img&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border-radius&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take2&lt;/span&gt;&lt;span&gt; .img&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  width&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border-radius&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  background-color&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;black&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take2&lt;/span&gt;&lt;span&gt; .indicator&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  width&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;absolute&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take2&lt;/span&gt;&lt;span&gt; .indicator1&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  bottom&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-3.5&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  right&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-3.5&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take2&lt;/span&gt;&lt;span&gt; .indicator2&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  top&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-3.5&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  left&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-3.5&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;horiz&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take2&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/randomlogo.png&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator indicator2 orange&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator indicator1 green&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take2&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;img&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator indicator2 orange&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator indicator1 green&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Huh?? You may have many questions, such as “why not just put
&lt;code&gt;class=&quot;indicator2&quot;&lt;/code&gt; outside the part that clips?” and “wait hold on why is is
clipping like that in the first place?” The answers to which are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;React Component Hierarchy&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;: it’s simpler to make a component that says “I
want to optionally add exactly one new indicator” on something than so say
“I want to add a configurable number of indicators with variable
positions”, because otherwise you have to somehow blend the masks which can
get hairy&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;We’re Getting To That&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It may have been wiser to bite the bullet and figure out how to reorganize the
component hierarchy, but now I was curious to get to the bottom of this and
figure out if I could do something about the first problem at the same time.&lt;/p&gt;
&lt;p&gt;Poking around in developer tools, we can confirm that it’s &lt;em&gt;just&lt;/em&gt; the &lt;code&gt;mask&lt;/code&gt;
property causing this clipping. With the mask on, affecting the bottom right
corner, we suddenly get clipping in the top left. A panicked search for “mask
clips things that it shouldn’t” brings us to the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/mask-clip&quot;&gt;mask-clip&lt;/a&gt;
property. Swell! Let’s just specify &lt;code&gt;no-clip&lt;/code&gt; then, and:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Great!! Seems we’re done then, no? Ignoring the slight imperfection in the
mask, of course. Well, if we happen to move &lt;code&gt;.indicator2&lt;/code&gt; to the right side, then…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take2&lt;/span&gt;&lt;span&gt; .indicator3&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  top&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-3.5&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  right&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-3.5&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;horiz&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take2&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp noclip&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/randomlogo.png&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator indicator3 orange&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator indicator1 green&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take2&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp noclip&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;img&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator indicator3 orange&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;indicator indicator1 green&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;HUH. WHAT. That’s strange, to say the least. All we did was change &lt;code&gt;left: -3.5px&lt;/code&gt; to &lt;code&gt;right: -3.5px&lt;/code&gt; and suddenly the top is shorn off?? Playing around a
bit more and setting &lt;code&gt;right: 10px&lt;/code&gt;, we see a clue:&lt;/p&gt;

&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;That indentation in where it gets cut off is suspicious.. it’s almost like…&lt;/p&gt;
&lt;h3&gt;The Mask Is Repeating&lt;/h3&gt;
&lt;p&gt;That is, when the content goes outside the bounding box, a duplicate copy of
the mask is placed there. Skimming the sidebar of the MDN tab where we found
mask-clip, we do indeed see there is a
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/mask-repeat&quot;&gt;mask-repeat&lt;/a&gt;
property, whose default value implies this exact behavior. Attempting to set
&lt;code&gt;no-repeat&lt;/code&gt; on the mask, however, just results in it clipping again.&lt;/p&gt;
&lt;h2&gt;Problem 3: It’s Problem 1 Again, But Different&lt;/h2&gt;
&lt;p&gt;The designer comes back and says “that indicator in the top right is actually
meant to be an unread message count, and should have a pill-shaped mask.” OK,
no problem, some reading of MDN has us come across the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/mask-composite&quot;&gt;mask-composite&lt;/a&gt;
property, and a bit of fooling around with it later we have a prototype:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;.take3&lt;/span&gt;&lt;span&gt; .pfp&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  border-radius&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-image&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    radial-gradient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      ellipse&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; at&lt;/span&gt;&lt;span&gt; 80&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      transparent&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      white&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    linear-gradient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      to&lt;/span&gt;&lt;span&gt; bottom&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      white&lt;/span&gt;&lt;span&gt; 40&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      transparent&lt;/span&gt;&lt;span&gt; 40&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    linear-gradient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      to&lt;/span&gt;&lt;span&gt; left&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      transparent&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      white&lt;/span&gt;&lt;span&gt; 20&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  mask-composite&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;subtract&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;horiz&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take3&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;/randomlogo.png&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;avatar take3&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &amp;lt;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pfp&quot;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt; &lt;div&gt;&lt;div&gt;&lt;img src=&quot;/randomlogo.png&quot; /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I could not honestly tell you how this works, only that it does. But as you can
see from this image (and maybe even on your browser!), there’s a huge problem:
not only is the circular part of the mask not anti-aliased, but &lt;strong&gt;&lt;em&gt;it’s not
even masking the anti-aliased pixels from the &lt;code&gt;border-radius&lt;/code&gt;&lt;/em&gt;&lt;/strong&gt;. This is the
clearest demonstration of the WebKit bug I was promising to expose in this
post, so here you go :)&lt;/p&gt;
&lt;h2&gt;A Better(?) Approach&lt;/h2&gt;
&lt;p&gt;Fortunately, that same day I found this bug I also came up with an approach
that solves all of these problems, at a small cost to generated code size. But
this post is long enough as it is already, and you’re probably fatigued reading
this, so I think I’ll leave that for a follow-up post.&lt;/p&gt;
&lt;p&gt;As an aside, Markdown is really nice for things like this. I can just include
HTML right in with the rest of the formatted text and it just works?? Magical.&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You’ve read the rest of the post. You know this isn’t actually easy. &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Yes, we ship a React.js Electron app. Yes, the performance is much of a
problem as you think it is. I will not be taking any questions about this. &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As if I didn’t end up writing something like that anyways, lol &lt;a href=&quot;#user-content-fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>programming</category><category>Web</category><category>Chrome</category></item><item><title>New Blog Framework: Astro</title><link>https://www.hazelduvall.dev/blog/posts/2023-10-22-new-blog-framework.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-10-22-new-blog-framework.html</guid><description>I explain the new static site generator I&apos;m using for my blog, Astro, and why I&apos;m using it over my old one, Hakyll.</description><pubDate>Sun, 22 Oct 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;2022-12-29-i-dont-actually-like-hakyll-that-much.html&quot;&gt;I was fed up with Hakyll&lt;/a&gt;, so I’ve switched my site to use a new blogging framework, &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The reasons for this are twofold:&lt;/p&gt;
&lt;h2&gt;Hakyll Stank&lt;/h2&gt;
&lt;p&gt;I covered this in more detail in my last post, but the overall gist is that Hakyll deploys were way too slow for me. I spent a long time setting up Github Actions correctly, only for them to get no speedup in the average case because the cache entries expire in between the (very long) periods between my posts. I &lt;em&gt;could&lt;/em&gt; just&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;aws&lt;/span&gt;&lt;span&gt; s3&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; --delete&lt;/span&gt;&lt;span&gt; _site/&lt;/span&gt;&lt;span&gt; s3://www.hazelduvall.dev/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;every time I updated my site and just have everything locally since I’m running the preview server that automatically populates the build directory anyways, but gosh darn it I’m just unreasonably attached to CI. Main benefit: it lets me have “draft” posts by just not publishing them to git. (that’s kind of it)&lt;/p&gt;
&lt;h2&gt;Astro Is Nice&lt;/h2&gt;
&lt;p&gt;I tried it out for another website (that I made after this one) and really enjoyed it. Much easier to get set up than something like Hakyll for sure. Also more flexible than something like &lt;a href=&quot;https://www.getzola.org/&quot;&gt;Zola&lt;/a&gt;, which I used for my Rust Stuco Website. My blog has gotten a bit complicated in places, what with the post links and the &lt;a href=&quot;/photography.html&quot;&gt;Photography page&lt;/a&gt;, so having full componentized control over things is nice. Plus, I’m now even more used to thinking in the component model thanks to what I do for work (tho, I’m still not that good at it).&lt;/p&gt;
&lt;p&gt;I did need quite a few hacks to get it to work tho. Biggest thing was doing the equivalent of &lt;a href=&quot;https://docs.astro.build/en/guides/imports/#astroglob&quot;&gt;&lt;code&gt;Astro.glob&lt;/code&gt;&lt;/a&gt;. The docs mention that you can use Vite’s &lt;code&gt;import.meta.glob&lt;/code&gt; instead, but don’t really provide any examples. Lacking any examples on the internet, I stumbled my way around typescript to find the following solution:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// file:src/env.d.ts&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// the order here is important! Astro&apos;s `import.meta.glob` typing is broken for me :(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;/// &amp;lt;&lt;/span&gt;&lt;span&gt;reference&lt;/span&gt;&lt;span&gt; types&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;vite/client&quot;&lt;/span&gt;&lt;span&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;/// &amp;lt;&lt;/span&gt;&lt;span&gt;reference&lt;/span&gt;&lt;span&gt; types&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;astro/client&quot;&lt;/span&gt;&lt;span&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// file:src/data/posts.ts&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// A `MarkdownInstance` is the output from Astro&apos;s integration of Vite when it imports markdown files from a glob&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt; { MarkdownInstance } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &quot;astro&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// A `AstroComponentFactory` represents a component object that can be used like `&amp;lt;Component /&amp;gt;` instead of `{Component}` in the body of the Astro component it&apos;s included into. Import looks a little strange but it&apos;s fine :P&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt; { AstroComponentFactory } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &quot;astro/runtime/server/index.js&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// Interface for the frontmatter in the posts&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;interface&lt;/span&gt;&lt;span&gt; RawPost&lt;/span&gt;&lt;span&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// Interface for the components passed to the eventual post component&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;interface&lt;/span&gt;&lt;span&gt; PostProps&lt;/span&gt;&lt;span&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; interface&lt;/span&gt;&lt;span&gt; PostPropsWithComponent&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; PostProps&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  Content&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; AstroComponentFactory&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; getPosts&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; ()&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;PostPropsWithComponent&lt;/span&gt;&lt;span&gt;[]&amp;gt; &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; rawPosts&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; import&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;meta&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;glob&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;MarkdownInstance&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;RawPost&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &quot;../posts/*.markdown&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; posts&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Object.&lt;/span&gt;&lt;span&gt;values&lt;/span&gt;&lt;span&gt;(rawPosts).&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;producer&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; post&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; producer&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; props&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; PostPropsWithComponent&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        Content: post.Content,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      return&lt;/span&gt;&lt;span&gt; props;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; posts;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hereby release the above code snippet under an MIT license, or something. Basically, feel free to adapt and extend as you see fit, just link to this blog post or something :P&lt;/p&gt;
&lt;p&gt;Other nice things I got out of Astro:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Built-in code highlighting for language-tagged code blocks. (It would’ve been theoretically possible but kind of hard with Hakyll, so very nice to get that for free!)&lt;/li&gt;
&lt;li&gt;Built-in image optimization (I haven’t used it yet since it would require further restructuring)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;LaTeX\LaTeX&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;E&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, via &lt;code&gt;remark-math&lt;/code&gt; and &lt;code&gt;rehype-katex&lt;/code&gt; plugins (&lt;em&gt;very&lt;/em&gt; easy to install!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What’s Next?&lt;/h2&gt;
&lt;p&gt;Not sure! One thing I’d like to do is update this blog’s theming. Not too big a fan of the font anymore, nor some of the color/layout choices of the Wordpress Twenty Fifteen theme (yes, really) (still the best of the default Wordpress themes, imo). That smells suspiciously like doing even more rewrites of my blog, though, so perhaps I’ll leave that alone for now :)&lt;/p&gt;</content:encoded><category>Web</category><category>Astro</category></item><item><title>I&apos;m A Maintainer Now??</title><link>https://www.hazelduvall.dev/blog/posts/2023-10-11-im-a-maintainer-now.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-10-11-im-a-maintainer-now.html</guid><description>Recollections on how I got myself into the position of maintaining a fairly large (if not that popular nor crucial) open-source library, node-webrtc, while getting paid for it.</description><pubDate>Wed, 11 Oct 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, some code I hacked on for work made its way onto &lt;a href=&quot;https://news.ycombinator.com/item?id=37774807&quot;&gt;Hacker
News&lt;/a&gt;, where it got a decent
amount of attention. Nothing crazy, but enough that I was pleasantly surprised.&lt;/p&gt;
&lt;p&gt;The code in question is
&lt;a href=&quot;https://github.com/node-webrtc/node-webrtc&quot;&gt;node-webrtc&lt;/a&gt;, specifically, my
&lt;a href=&quot;https://github.com/WonderInventions/node-webrtc&quot;&gt;fork&lt;/a&gt; of it. This is an NPM
package for letting NodeJS access WebRTC APIs normally only accessible in
browsers. It does this by taking the
&lt;a href=&quot;https://webrtc.googlesource.com/src/&quot;&gt;original&lt;/a&gt; libwebrtc source code and
plugging it into &lt;a href=&quot;https://nodejs.org/api/addons.html&quot;&gt;Node Native Addon&lt;/a&gt;
bindings that closely mirror the ones in the WebRTC specification.&lt;/p&gt;
&lt;p&gt;I needed to fork this package because the original became unmaintained in 2021,
and had suffered enough bitrot when it came to the Node Native Addon side of
things that it no longer worked with the latest Node LTS (18). In order to use
it in our codebase (for various reasons), it needed to be upgraded.&lt;/p&gt;
&lt;p&gt;In addition to the upgrade of the APIs, I also started to upgrade the version
of libwebrtc it was building against, also because our code needed features
from slightly newer versions. I upgraded it from M87 to M94, going through M90
and M92 first, and am in the middle of upgrading to M98. These incremental
steps proved to be the best option for getting things working (hard to fix
things when everything is broken, better to only break a few things at a time),
but means it’s slow progress towards an eventual goal of M118 and our patched
version of libwebrtc.&lt;/p&gt;
&lt;p&gt;This is all well and good, and once I was moved to another project I thought
this would effectively be the end of the saga. I did want to keep working on
it, but other tasks needed doing! It wasn’t until the Hacker News post came
around that I caught the attention of node-webrtc’s previous maintainer, who
offered to hand over ownership of the Github organization and NPM package.&lt;/p&gt;
&lt;p&gt;So, yeah, that happened! I haven’t merged my fork back into upstream yet, nor
added a new NPM package version. This is because I am still working on other
tasks for Roam and haven’t put a lot of time into this library recently. I’ll
keep plugging away at it when I can, and will be responsive to Github issues on
the fork during normal business hours. Not sure what the appropriate channels
are to make an announcement when I do make the changeover, perhaps just a note
in the &lt;code&gt;README.md&lt;/code&gt; is appropriate.&lt;/p&gt;
&lt;p&gt;This feels surreal! Very interesting to have a codebase dumped on me like that,
just because I put in the work for it. No pressure or anything since it doesn’t
seem widely used, but still thinking about how to uphold a legacy and start
building a reputation more. I would like to be able to devote more energy
towards improving open source and building cool stuff people can see that has
my name on it. Frontend work is cool and all, but this is more the stuff I
signed up for really when I wanted to become a Software Engineer.&lt;/p&gt;</content:encoded><category>WebRTC</category></item><item><title>Remember to Munge Your Headers!</title><link>https://www.hazelduvall.dev/blog/posts/2023-09-08-munge-your-headers.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-09-08-munge-your-headers.html</guid><description>A writeup of a bug I encountered while working on some WebRTC code for Roam. Contains my debugging process and a solution to a probably-not-too-common problem.</description><pubDate>Fri, 08 Sep 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So for work, I’ve been hacking on the Selective Forwarding Unit
(&lt;a href=&quot;https://webrtc.ventures/2020/12/webrtc-media-servers-sfus-vs-mcus/&quot;&gt;SFU&lt;/a&gt;)
that we use to send media between clients. Through this, I’ve found a couple
bugs, one of which had quite a long but rewarding debugging journey.&lt;/p&gt;
&lt;h2&gt;The Bug&lt;/h2&gt;
&lt;p&gt;This bug manifested in such a weird way that I didn’t actually catch it at
first. Regular audio and video streams worked just fine. Screenshares
would start, but then crawl to a halt after the first few frames, or after a
couple seconds. I wasn’t catching this bug at first because I was sharing my
static desktop and wasn’t expecting it to change; only after I started doing
more intensive tests, running a clock on the screenshare for exact timing, did
I notice that things were weird.&lt;/p&gt;
&lt;h2&gt;Debugging&lt;/h2&gt;
&lt;p&gt;At this point, I had done enough other debugging to have a fairly standard
checklist of things to look at. As usual, &lt;a&gt;chrome://webrtc-internals&lt;/a&gt; was my
go-to.&lt;/p&gt;
&lt;p&gt;Looking at the graphs for the screenshare upload, I was seeing plenty of
packets sent, as well as a burst of packets whenever there was large activity
on the screen.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;outbound-rtp graphs&quot; loading=&quot;lazy&quot; width=&quot;876&quot; height=&quot;433&quot; src=&quot;/_astro/2023-09-08-1_1gMxT9.webp&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;remote-inbound-rtp graphs&quot; loading=&quot;lazy&quot; width=&quot;662&quot; height=&quot;579&quot; src=&quot;/_astro/2023-09-08-2_Z11zFuB.webp&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So, I could rule out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The upload transceiver not getting created&lt;/li&gt;
&lt;li&gt;The connection not getting negotiated&lt;/li&gt;
&lt;li&gt;The upload MediaStream not getting attached to the transceiver&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, I looked at the download side. I saw a graph that matched almost exactly
what I was seeing on the screen: a burst of packets, and then nothing.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;inbound-rtp graphs&quot; loading=&quot;lazy&quot; width=&quot;736&quot; height=&quot;598&quot; src=&quot;/_astro/2023-09-08-3_Z1riimj.webp&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Because I was seeing &lt;em&gt;something&lt;/em&gt;, I could rule out the same things as with the
upload. Which was concerning, because up until this point that’s all I had been
checking. It seemed I needed to dig a little further.&lt;/p&gt;
&lt;p&gt;I first fired up Wireshark to confirm that, indeed, packets &lt;em&gt;were&lt;/em&gt; actually
being sent from the SFU to the downloader. This was weird to me, since
Wireshark was reporting packets being sent even though Chrome wasn’t reporting
any packets&lt;/p&gt;
&lt;p&gt;I then ran Chrome in &lt;a href=&quot;https://support.google.com/chrome/a/answer/6271282?hl=en&quot;&gt;debug logging mode&lt;/a&gt;
and looking at a live tail of &lt;code&gt;chrome_debug.log&lt;/code&gt;. In this, I saw a very
suspicious log message being spammed a bunch as soon as the faulty screenshare
started:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;[6612:28688:1011/191519.091:VERBOSE1:rtp_transport.cc(196)] Failed to demux&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;RTP packet: PT=96 SSRC=2139439780 MID=e^A&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;[6612:28688:1011/191519.091:VERBOSE1:rtp_transport.cc(196)] Failed to demux&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;RTP packet: PT=96 SSRC=2139439780 MID=e^B&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;[6612:28688:1011/191519.091:VERBOSE1:rtp_transport.cc(196)] Failed to demux&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;RTP packet: PT=96 SSRC=2139439780 MID=e^C&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those &lt;code&gt;^&lt;/code&gt; characters were actually unprintable! (Just had to reproduce them
here as text). It was looking like uninitialized memory, or a counter, and the
very least, something that should never have been encoded as text. The
&lt;a href=&quot;https://webrtc.googlesource.com/src/+/branch-heads/5845/pc/rtp_transport.cc#196&quot;&gt;relevant line in chromium&lt;/a&gt;
confirmed that
&lt;a href=&quot;https://webrtc.googlesource.com/src/+/branch-heads/5845/call/rtp_demuxer.cc#100&quot;&gt;yes&lt;/a&gt;,
something was going very wrong, since this value should always be a string in a
properly-encoded packet. Somehow, the SFU was sending malformed packets!&lt;/p&gt;
&lt;h3&gt;Where Does This Value Come From?&lt;/h3&gt;
&lt;p&gt;This MID (Media Identifier) value is supposedly to distinguish between
different media sections when multiple are bundled together. In practice, the
SSRC (Synchronization Source) value seems to be more than enough, but the
WebRTC standard
&lt;a href=&quot;https://w3c.github.io/webrtc-extensions/#rtp-header-extension-control-transceiver-interface&quot;&gt;requires&lt;/a&gt;
that MIDs be supported if multiple streams are bundled in one connection. To
save on the overhead of creating connections, we do bundle the screenshare
downloads with the camera downloads, and looking at the session descriptions it
was clear that this header extension was being negotiated.&lt;/p&gt;
&lt;h3&gt;What Are Header Extensions?&lt;/h3&gt;
&lt;p&gt;Header Extensions are defined in
&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc8285.html#section-4&quot;&gt;RFC8285&lt;/a&gt; and are
basically little bits of extra data that don’t need to be in all RTP packets,
and are negotiated per-stream like everything else in the SDP&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. To save on
bandwidth, each of the possible header extensions represented by a URI
(Universal Resource Identifier) gets mapped to an ID determined by the offering
participant. An example mapping looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;a=extmap:3&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that packets will have data for header extension ID 3 is fed into
the transport-wide congestion control mechanism, and data for header extension
ID 4 is the MID for the packet.&lt;/p&gt;
&lt;p&gt;Because the malformed MIDs are specified in a header extension, I decided to
dump all header extensions for screenshare packets coming out of the SFU, and
sure enough, the header extension ID for the MID extension was present and
being set to invalid values!&lt;/p&gt;
&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;Due to the nature of the SFU, the header extension id mappings can be different
for the uploading participant and the downloading participant. And, as it
turned out, we were not properly stripping all header extensions from uploader
packets before forwarding them to the downloaders. The correct thing to do
(which we were already doing for some header extensions) is to store any header
extension data out-of-band for forwarded packets, and just before sending the
packet to the downloader, add back in the header extensions with the correct
ids for that download stream.&lt;/p&gt;
&lt;p&gt;And that’s it! Hope you were able to take something away from this debugging
journey, I sure learned a lot about WebRTC as I went.&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The SDP also contains negotiation for media codecs, codec extensions,
what streams exist, etc. &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>programming</category><category>Web</category><category>WebRTC</category></item><item><title>WebRTC Perfect Negotiation</title><link>https://www.hazelduvall.dev/blog/posts/2023-08-30-webrtc-perfect-negotiation.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-08-30-webrtc-perfect-negotiation.html</guid><description>An addendum to the seminal Firefox blog post about Perfect Negotiation in WebRTC</description><pubDate>Wed, 30 Aug 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As part of my job, I have been working pretty closely with
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API&quot;&gt;WebRTC&lt;/a&gt;, a
technology for doing real-time audio/video communications. It’s an open
standard steered entirely &lt;em&gt;ahem&lt;/em&gt; supported by Chrome, so it’s the natural
choice for anything Electron-based.&lt;/p&gt;
&lt;p&gt;It’s a peer-to-peer technology, so part of the standard includes specifications
for how the peers do a dance for agreeing on who’s sending what tracks, who’s
initiating the TLS encryption, what are the mutually supported codecs anyways,
that sort of stuff. This gets pretty complex since it’s all being done over the
network, asynchronously. &lt;a href=&quot;https://blog.mozilla.org/webrtc/perfect-negotiation-in-webrtc/&quot;&gt;Perfect
Negotiation&lt;/a&gt;,
then, is a way of setting up the callbacks for this negotiation such that
everything “just works” and both sides can use higher-level APIs instead of
worrying about the nitty-gritty.&lt;/p&gt;
&lt;p&gt;The blog post linked above does an excellent job of explaining the concept in
more depth and providing code to go along with it. However, it’s actually
slightly incorrect in my experience!&lt;/p&gt;
&lt;p&gt;In the section for handling remote session descriptions, there is a piece of
code that goes like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (description.type &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &quot;offer&quot;&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; pc.signalingState &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; &quot;stable&quot;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;polite) &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    pc.&lt;/span&gt;&lt;span&gt;setLocalDescription&lt;/span&gt;&lt;span&gt;({ type: &lt;/span&gt;&lt;span&gt;&quot;rollback&quot;&lt;/span&gt;&lt;span&gt; }),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    pc.&lt;/span&gt;&lt;span&gt;setRemoteDescription&lt;/span&gt;&lt;span&gt;(description),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ]);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; pc.&lt;/span&gt;&lt;span&gt;setRemoteDescription&lt;/span&gt;&lt;span&gt;(description);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (description.type &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &quot;offer&quot;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; pc.&lt;/span&gt;&lt;span&gt;setLocalDescription&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; pc.&lt;/span&gt;&lt;span&gt;createAnswer&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  io.&lt;/span&gt;&lt;span&gt;send&lt;/span&gt;&lt;span&gt;({ description: pc.localDescription });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error is as follows: calling &lt;code&gt;setLocalDescription({type: &quot;rollback&quot;})&lt;/code&gt; in
Chrome when &lt;code&gt;pc.signalingState === &quot;stable&quot;&lt;/code&gt; will throw an error. Additionally,
Chrome doesn’t seem to guarantee the promises inside &lt;code&gt;Promise.all&lt;/code&gt; are
necessarily run in order. So, the correct code would actually be something
like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (description.type &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &quot;offer&quot;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;polite &lt;/span&gt;&lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; pc.signalingState &lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; &quot;stable&quot;&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    async&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&amp;gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (pc.signalingState &lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; &quot;stable&quot;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        await&lt;/span&gt;&lt;span&gt; pc.&lt;/span&gt;&lt;span&gt;setLocalDescription&lt;/span&gt;&lt;span&gt;({ type: &lt;/span&gt;&lt;span&gt;&quot;rollback&quot;&lt;/span&gt;&lt;span&gt; });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    pc.&lt;/span&gt;&lt;span&gt;setRemoteDescription&lt;/span&gt;&lt;span&gt;(description),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ]);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; pc.&lt;/span&gt;&lt;span&gt;setLocalDescription&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; pc.&lt;/span&gt;&lt;span&gt;createAnswer&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  io.&lt;/span&gt;&lt;span&gt;send&lt;/span&gt;&lt;span&gt;({ description: pc.localDescription });&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; pc.&lt;/span&gt;&lt;span&gt;setRemoteDescription&lt;/span&gt;&lt;span&gt;(description);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The original blog post seems to assume that the order of arguments to
&lt;code&gt;Promise.all&lt;/code&gt; will control the order more than I have observed.
&lt;code&gt;setLocalDescription&lt;/code&gt; may be queued first, but it isn’t necessarily polled to
completion first; in &lt;a&gt;chrome://webrtc-internals&lt;/a&gt;, I see &lt;code&gt;setLocalDescription&lt;/code&gt;
queued before &lt;code&gt;setRemoteDescription&lt;/code&gt;, but &lt;code&gt;setRemoteDescriptionOnSuccess&lt;/code&gt;
before &lt;code&gt;setLocalDescriptionOnFailure&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Not sure if this information is present anywhere else online, I sure couldn’t
find it when searching for “Failed to execute ‘setLocalDescription’ on
‘RTCPeerConnection’: Called in wrong signalingState: stable”. Not that it will
matter, my blog has terrible SEO lol.&lt;/p&gt;</content:encoded><category>programming</category><category>Web</category><category>WebRTC</category></item><item><title>Whoops! Let&apos;s Get Back To Posting</title><link>https://www.hazelduvall.dev/blog/posts/2023-06-17-whoops.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-06-17-whoops.html</guid><description>I seem to have fallen behind on updating this blog. I don&apos;t excuse this, but do make promises about which posts I&apos;ll start backfilling.</description><pubDate>Sat, 17 Jun 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I seem to have fallen behind on updating this blog! A lot of important life
events have occurred, which I probably should have blogged about at the time
when they were still fresh:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My final semester at college&lt;/li&gt;
&lt;li&gt;Graduating from college&lt;/li&gt;
&lt;li&gt;Starting my job&lt;/li&gt;
&lt;li&gt;Some secret fourth thing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ll backfill these posts in the coming days (weeks?) now that I have &lt;em&gt;even
better&lt;/em&gt; CI for this site. Riiiight after I change all the links from
sequentially numbered to date-and-title format, breaking all my SEO that was
never there in the first place :P&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Starting Work</title><link>https://www.hazelduvall.dev/blog/posts/2023-05-31-starting-work.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-05-31-starting-work.html</guid><description>I&apos;ve moved out of Pittsburgh into the beautiful borough of Brooklyn, NYC! I&apos;m now no longer a college student, but a full-time remote work Software Engineer at a hot startup! Wow look at me go!</description><pubDate>Wed, 31 May 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow! It sure does feel weird to no longer be a college student any more.&lt;/p&gt;
&lt;p&gt;After the usual craziness that is moving between apartments, I have settled in
Brooklyn, NY, the city right next to the Big Apple, for at least until the
lease expires.&lt;/p&gt;
&lt;p&gt;Here, I’ll be doing remote work for a remote work company,
&lt;a href=&quot;https://ro.am/about&quot;&gt;Roam&lt;/a&gt;!. I talked about them
&lt;a href=&quot;2022-12-12-first-job-secured.html&quot;&gt;earlier&lt;/a&gt;, but today was my first day
so it’s really official.&lt;/p&gt;
&lt;p&gt;Team seems nice, work seems interesting, it’s a pretty big codebase to learn
but I’ll get right on it!&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Roam</category></item><item><title>Graduation!</title><link>https://www.hazelduvall.dev/blog/posts/2023-05-14-graduated.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-05-14-graduated.html</guid><description>I graduated from college!</description><pubDate>Sun, 14 May 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A &lt;strong&gt;&lt;em&gt;ton&lt;/em&gt;&lt;/strong&gt; of extended relatives came out to see me graduate, which was super
kind of them and honestly pretty fun to hang out with.&lt;/p&gt;
&lt;p&gt;I can’t believe I’m finally done with it! I had some good times, some bad
times, made a lot of friends, took a lot of classes, and the best part is, I
don’t think I have regrets really. I made the most out of what I had, which was
a lot, and had fun while doing it.&lt;/p&gt;
&lt;p&gt;So long CMU, thanks for the memories!&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>I Was An OS TA</title><link>https://www.hazelduvall.dev/blog/posts/2023-05-05-i-was-an-os-ta.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-05-05-i-was-an-os-ta.html</guid><description>In the Spring 2023 Semester at CMU, I was a TA for Operating Systems Design and Implementation (15-410). In this post, I reminisce about the experience and what I learned from it.</description><pubDate>Fri, 05 May 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow. I actually made it. Since early-ish at CMU, I had known that an “OS TA”
was a laudable thing to be&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, but after &lt;a href=&quot;./2022-05-11-the-os-semester.html&quot;&gt;The OS
Semester&lt;/a&gt;, I wasn’t sure I’d actually be
one. Sure, I’d applied the &lt;a href=&quot;./2022-10-19-taing.html&quot;&gt;semester I was already scheduled to be a TA for
15-316&lt;/a&gt;, and applied again “just in case”, but I
didn’t &lt;em&gt;really&lt;/em&gt; think I’d actually get it. It was only (checks notes)
&lt;strong&gt;December 24th&lt;/strong&gt; that I found out for sure, through a friend refreshing the TA
assignment page for their own position. What a Christmas present lol.&lt;/p&gt;
&lt;p&gt;This final semester at CMU, I only took &lt;a href=&quot;http://15462.courses.cs.cmu.edu/spring2023/&quot;&gt;15-462 Computer
Graphics&lt;/a&gt;, so I had plenty of time
to attend another class, do research for a professor, teach &lt;a href=&quot;https://rust-stuco.github.io/&quot;&gt;my
stuco&lt;/a&gt;, and TA this class. hm. work expands to
fill the available time, huh?&lt;/p&gt;
&lt;h2&gt;What Does An OS TA Do?&lt;/h2&gt;
&lt;p&gt;In a nutshell:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;grade projects&lt;/li&gt;
&lt;li&gt;hold office hours&lt;/li&gt;
&lt;li&gt;slowly add to existing projects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in collaboration with &lt;a href=&quot;https://www.cs.cmu.edu/~davide/&quot;&gt;Professor Dave
Eckhardt&lt;/a&gt;, who has been teaching the course
for long enough to have taught some current professors at CMU.&lt;/p&gt;
&lt;p&gt;Oh! Also! I was the only “official” TA that semester, all others were alumni or
PhD students kindly contributing in their spare time.&lt;/p&gt;
&lt;h3&gt;Grading&lt;/h3&gt;
&lt;p&gt;This is The Big One™. All 5 projects, 2 homeworks, a midterm, and a final.&lt;/p&gt;
&lt;p&gt;For those latter 3 categories of written assignment, it’s not too big a deal.
There are fairly standardized rubrics/methodologies for grading, and the main
feedback given is point values (which students can come into office hours to
discuss if they want). What makes OS grading so infamous&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; for its grading is
the sheer amount of extremely detailed feedback given on all the coding
projects.&lt;/p&gt;
&lt;p&gt;For those coding projects, there is a standard set of tests that the code has
to pass&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;, and then the rest of the points are left to Architecture and Code
Quality. How do you grade these? You read the code, of course! And by “you” I
mean “me and Dave and a small army of masters/PhD students/alumni”.&lt;/p&gt;
&lt;p&gt;Reading all the code written by other students (especially by masters
students!) was really useful. It made me appreciate my own coding style&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;
also opened my eyes to other things you should pay attention to while coding.&lt;/p&gt;
&lt;p&gt;I will be part of the “small army” next semester&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;, and will be more than
happy to help read more code :)&lt;/p&gt;
&lt;h3&gt;Office Hours&lt;/h3&gt;
&lt;p&gt;As the only “official” TA, I did hold a lot of office hours. Dave (Eckhardt)
and Dave (O’Halloran) also held their own professor office hours, and a few
alumni held remote office hours on weekends.&lt;/p&gt;
&lt;p&gt;In office hours, I was supposed to never give out solutions, only ask questions
about what they had tried and hadn’t tried in an attempt to get them to think
about the problem more fully. This method is difficult and frustrating on both
sides but on the whole I agree that it does lead to better learning outcomes.&lt;/p&gt;
&lt;p&gt;I stuck to a fairly regular schedule and was always surprised by when students
did or didn’t come in. There were sometimes big influxes after an assignment
was released, right before it was due, or even just in the middle, but just as
often those times would be empty. And I would work on grading during the
downtime instead (:&lt;/p&gt;
&lt;h3&gt;Adding To Existing Projects&lt;/h3&gt;
&lt;p&gt;Due to a limit on the number of hours I could work in a week&lt;sup&gt;&lt;a href=&quot;#user-content-fn-6&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;, and a general
sense of wanting to do other things besides OS, I unfortunately did not do a
whole lot of this. I tried my best at updating the VM infrastructure to the
&lt;a href=&quot;https://www.intel.com/content/www/us/en/developer/articles/tool/simics-simulator.html&quot;&gt;now-publicly available version&lt;/a&gt;
instead of the older still-proprietary one CMU uses, and failed due to
some very interesting reasons that I should probably write up some time.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;was&lt;/em&gt; able to write a small test program for P4 that ran on a hypervisor that
the students wrote, but really Dave did most of the tough stuff with super
funky cursed Assembly and I just had to understand why it worked and hook it up
into a small shell. It is called &lt;code&gt;dog&lt;/code&gt; and when you type “dog” it types out
“cat” instead, wow crazy.&lt;/p&gt;
&lt;h2&gt;Did I Enjoy It?&lt;/h2&gt;
&lt;p&gt;I think this was a very worthwhile experience! I highly respect Dave Eckhardt
so having more time to interact with him was fun. There were also some fun
parts to grading and office hours, but on the whole it was a lot of work. I
still would do it again though. Even if it feels like a slog during, I can come
out the other side feeling like “yeah, I Did That”. Just like &lt;a href=&quot;2022-05-11-the-os-semester.html#section-3&quot;&gt;taking
OS&lt;/a&gt;, I guess.&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It’s a TA for a 4xx-level class, after all! And a prestigious one at that &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For being perpetually late. I did the best I could to not continue this
trend, I believe a big reason is Dave taking on a huge workload and not
being able to deliver until it would be &lt;em&gt;exceedingly&lt;/em&gt; inappropriate not to,
not just regularly inappropriate. &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dave likes to say that “just passing all the tests will get you to a C”.
I cannot say enough about the grading mechanism to confirm nor deny the
veracity of this statement. &lt;a href=&quot;#user-content-fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Lots&lt;/em&gt; of documentation. Everywhere. Explain the why of every single
piece of code before I write it down because I &lt;em&gt;know&lt;/em&gt; I will forget stuff
later. &lt;a href=&quot;#user-content-fnref-4&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I needed basically the whole semester to get into a groove with grading,
and Dave joked that he wants a return on his investment. &lt;a href=&quot;#user-content-fnref-5&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;20 hours. That turned out to not be enforced at all, and I could go over very
easily without raising any flags it seemed. &lt;a href=&quot;#user-content-fnref-6&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>class review</category><category>CMU</category></item><item><title>Some Cool Labs I Helped Make, Pt. 2</title><link>https://www.hazelduvall.dev/blog/posts/2023-01-17-some-cool-labs-i-helped-make-p2.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-01-17-some-cool-labs-i-helped-make-p2.html</guid><description>In the Fall 2022 semester at CMU, I (as a TA) helped design and run some programming labs for 15-316 Software Foundations of Security and Privacy. I&apos;ll go over why I think these labs are really cool without giving away any hints that aren&apos;t already in the lab writeups. This post is about the second of the two labs</description><pubDate>Tue, 17 Jan 2023 12:00:00 GMT</pubDate><content:encoded>
&lt;p&gt;Read &lt;a href=&quot;./2023-01-16-some-cool-labs-i-helped-make.html&quot;&gt;Part 1&lt;/a&gt; first! That lab
was already super cool, but this one is even better imo 😎&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://github.com/15316-cmu/lab2-2022&quot;&gt;Lab 2: Authorization &amp;amp; Trust&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This lab is all about &lt;em&gt;writing an automated theorem prover&lt;/em&gt; for a limited set
of theorems to prove. As a part of that, you get to learn the answers to fun
questions like&lt;/p&gt;
&lt;h3&gt;What Does It Mean To Prove Something?&lt;/h3&gt;
&lt;p&gt;That is, how can we show something like &lt;span&gt;&lt;span&gt;(A→B)∧(B→C)→(A→C)(A \rightarrow B) \land (B \rightarrow C) \rightarrow (A \rightarrow C)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∧&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;C&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;C&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is true?&lt;/p&gt;
&lt;h4&gt;What Does It Mean For Something To Be True?&lt;/h4&gt;
&lt;p&gt;Great question! Is &lt;span&gt;&lt;span&gt;AA&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; true? Why not?&lt;/p&gt;
&lt;p&gt;The answer is, &lt;em&gt;it depends on your interpretation of &lt;span&gt;&lt;span&gt;AA&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/em&gt;. And I mean that
word “interpretation” quite literally, that’s the vocabulary we use for “the
assignment of truth values to variables.&lt;/p&gt;
&lt;p&gt;There is an interpretation where &lt;span&gt;&lt;span&gt;AA&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is true: &lt;span&gt;&lt;span&gt;{A:⊤}\{A: \top\}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;⊤&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, and an
interpretation where &lt;span&gt;&lt;span&gt;AA&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is false: &lt;span&gt;&lt;span&gt;{A:⊥}\{A: \bot\}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;⊥&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;So to be more precise, when we are asking if some logical formula is true, we
are really asking whether it is &lt;em&gt;true in all interpretations&lt;/em&gt;. Here’s some
symbols:&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;⊨P↔∀I.I⊨P\models P \leftrightarrow \forall I. I \models P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;⊨&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;↔&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∀&lt;/span&gt;&lt;span&gt;I&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;I&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;⊨&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;So Back To The Main Question: Proofs&lt;/h4&gt;
&lt;p&gt;So now we have this idea of interpretations, and truthiness from the standard
boolean connectives &lt;span&gt;&lt;span&gt;(∧,∨,→,¬)(\land, \lor, \rightarrow, \lnot)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;∧&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∨&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;¬&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, and need some way of
showing that a formula will hold under any interpretation. Not only that, the
way we do this needs to be in some format that a computer can quickly recognize
and manipulate, so text is right out&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The solution we use is &lt;strong&gt;proof transformation rules in a tree structure&lt;/strong&gt;. A
single rule might go something like this:&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;Γ,A⊢BΓ⊢A→B,Δ(→R)\frac{\Gamma,A \vdash B}{\Gamma \vdash A \rightarrow B, \Delta}(\rightarrow R)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Γ&lt;/span&gt;&lt;span&gt;⊢&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;Δ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Γ&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;⊢&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;→&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The more complex rule is at the bottom, and gets broken up into simpler
rules as you go up the tree. More explanations of symbols:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;⊢\vdash&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;⊢&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: If everything on the left side is true, then at least one thing
on the right right is true. Like a big implication but more flexible for
our needs.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;Γ,Δ\Gamma,\Delta&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Γ&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Δ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: Leftover clauses on the right and left hand sides of the
&lt;span&gt;&lt;span&gt;⊢\vdash&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;⊢&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; to signify which rule we are applying to and when we can carry
things over&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To finish a proof, you need to “close out” every single branch, signified by
&lt;span&gt;&lt;span&gt;⋆\star&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;⋆&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Here are some rules that do this:&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;⋆Γ⊢⊤,Δ(⊤)⋆Γ,⊥⊢Δ(⊥)⋆Γ,P⊢P,Δ(id)\frac{\star}{\Gamma \vdash \top, \Delta}(\top) \quad\quad \frac{\star}{\Gamma, \bot \vdash \Delta}(\bot) \quad\quad \frac{\star}{\Gamma,P \vdash P,\Delta}(id)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Γ&lt;/span&gt;&lt;span&gt;⊢&lt;/span&gt;&lt;span&gt;⊤&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;Δ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;⋆&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;⊤&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Γ&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;⊥&lt;/span&gt;&lt;span&gt;⊢&lt;/span&gt;&lt;span&gt;Δ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;⋆&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;⊥&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Γ&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;⊢&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;Δ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;⋆&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;These types of proofs (in the right format) can be easily checked by a
computer, since all it as to do is, for each proof rule, check that it was
applied properly. Then, since you know all the proof rules are valid, the
entire proof must be valid!&lt;/p&gt;
&lt;p&gt;Unfortunately, I can’t write out an example, since doing simple ones of those
is a homework problem early in the class, but u get the gist right? Moving on!&lt;/p&gt;
&lt;h3&gt;What Are We Trying To Prove, Exactly?&lt;/h3&gt;
&lt;p&gt;So imagine you are a smart door lock. You have some notion of “who is allowed
to access this door” and “who is allowed to delegate access to this door”.
These are can be encoded as affirmation logic&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; principles like:&lt;/p&gt;













&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;/th&gt;&lt;th&gt;B&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;door&lt;/code&gt; says &lt;code&gt;canopen(hazel)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;door&lt;/code&gt; says forall &lt;code&gt;p&lt;/code&gt;. (&lt;code&gt;hazel&lt;/code&gt; says &lt;code&gt;canopen(p)&lt;/code&gt;) implies &lt;code&gt;canopen(p)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;These statements have a close tie to cryptography! A “says” clause is like a
signed statement, and proving the identity of the signer requires knowing about
Certificate Authorities, and it all gets pretty complicated, but! &lt;em&gt;There is a
reason for all of it&lt;/em&gt; and &lt;em&gt;it can be automated very naturally&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The lab is then to present a series of virtual doors with the appropriate
signed statements and a proof using those statements to show that you can enter
the door. The proof goals are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Given a signed statement you can enter the door, construct enough of the rest
of the proof (with CAs and such) to get the “says” statement&lt;/li&gt;
&lt;li&gt;Given a delegation of authority, open the door&lt;/li&gt;
&lt;li&gt;Given a very broad transitive delegation policy, open the door&lt;/li&gt;
&lt;li&gt;Exploit the door’s certificate checking code to open a door you logically
shouldn’t be able to&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sounds simple right?? :)&lt;/p&gt;
&lt;p&gt;I really enjoy this lab because it combines together a lot of disparate topics
and they all still work together well, and it really shows the power of
computers to do Logic, very quickly, and it feels like magic.&lt;/p&gt;
&lt;p&gt;That’s pretty much all I can say without spoiling the rest of the lab, if this
still sounds interesting to you I think you should &lt;a href=&quot;https://github.com/15316-cmu/lab2-2022&quot;&gt;read
it&lt;/a&gt; and try it out! It is free! I
really appreciate that this course is just,, publicly available to anyone who
wants to learn it (even if the lectures really bring out the best in the
subject but i digress).&lt;/p&gt;
&lt;p&gt;That’s about it, thanks for reading!!&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Yes, not even ChatGPT can reliably do stuff like this 😔 &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As an exercise, convince yourself that all the proof rules I’ve shown are
true! &lt;a href=&quot;#user-content-fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Working with these “says” clauses is a little tricky and has a lot of
subtlety to it. If you’re interested in learning more, I highly recommend
reading the &lt;a href=&quot;https://15316-cmu.github.io/2022/schedule.html&quot;&gt;15-316 course
notes&lt;/a&gt;. They are available
for free online and are really comprehensive!! &lt;a href=&quot;#user-content-fnref-4&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>projects</category><category>CMU</category></item><item><title>Some Cool Labs I Helped Make</title><link>https://www.hazelduvall.dev/blog/posts/2023-01-16-some-cool-labs-i-helped-make.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-01-16-some-cool-labs-i-helped-make.html</guid><description>In the Fall 2022 semester at CMU, I (as a TA) helped design and run some programming labs for 15-316 Software Foundations of Security and Privacy. I&apos;ll go over why I think these labs are really cool without giving away any hints that aren&apos;t already in the lab writeups. This post is about the first of the two labs.</description><pubDate>Mon, 16 Jan 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As a full disclaimer, the vast majority of work for these labs was done by the
professor for &lt;a href=&quot;https://15316-cmu.github.io/&quot;&gt;15-316 Software Foundations of Security and
Privacy&lt;/a&gt;, &lt;a href=&quot;https://www.cs.cmu.edu/~mfredrik/&quot;&gt;Matt
Fredrikson&lt;/a&gt;. As a TA, I helped a little bit
with coming up with the ideas for the labs and also a little with basic
file/object structure and autograders.&lt;/p&gt;
&lt;p&gt;So, while I can’t really even claim 20% credit for these, I’m still really
proud that I had any part in them that all and think they are super neat labs
to work through. Also, they’re open source so you can follow along at home too!&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://github.com/15316-cmu/lab1-2022&quot;&gt;Lab 1: Analyzing Safety&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This lab is all about &lt;em&gt;instrumenting code&lt;/em&gt; and then &lt;em&gt;proving properties about
the original code through the instrumented version&lt;/em&gt;. You may be wondering what
any of these words mean so let’s go through an example.&lt;/p&gt;
&lt;h3&gt;Tinyscript&lt;/h3&gt;
&lt;p&gt;Here is some code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;x := i;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;while x &amp;lt; (i-i)-1 do&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    x := x + 1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may notice that the syntax is similar to, but not exactly the same as, any
language you’ve ever seen&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. This is because it is a language you have never
seen. For simplicity, this course uses a fairly small language we call
Tinyscript with simple and intuitive and easy-to-specify semantics. Full syntax
tree and interpreter can be found in the repository.&lt;/p&gt;
&lt;h3&gt;Safety Properties&lt;/h3&gt;
&lt;p&gt;Anyways back to safety: a &lt;strong&gt;&lt;em&gt;safety property&lt;/em&gt;&lt;/strong&gt; is class&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; of traces that can be
defined by excluding all failing traces&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; with just a finite prefix. That is,
as soon as you see “something unsafe”, you know the safety property has been
violated.&lt;/p&gt;
&lt;p&gt;Unfortunately, you can’t neatly divide programs into “satisfies a safety
property” and “doesn’t satisfy a safety property” since that would require
solving the halting problem&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. Plus, with our arbitrary-precision variables,
you can’t brute-force every input combination to see if the safety property is
violated (or the program doesn’t halt in a reasonable amount of time). So, what
can you do?&lt;/p&gt;
&lt;h3&gt;Dynamic Logic&lt;/h3&gt;
&lt;p&gt;There is a formula called a &lt;strong&gt;&lt;em&gt;box modality&lt;/em&gt;&lt;/strong&gt;, which we denote as &lt;span&gt;&lt;span&gt;[α]P[\alpha]P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
where &lt;span&gt;&lt;span&gt;α\alpha&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is a program, and &lt;span&gt;&lt;span&gt;PP&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is a boolean predicate, which is
itself a predicate saying “for all runs of &lt;span&gt;&lt;span&gt;α\alpha&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, &lt;span&gt;&lt;span&gt;PP&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; will hold in the
terminating state”.&lt;/p&gt;
&lt;p&gt;Turns out, there are rules on how to simplify this when given a specific
&lt;span&gt;&lt;span&gt;α\alpha&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span&gt;&lt;span&gt;PP&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;! I’ll spare you most of the details (take the class or
read the code to see how it’s done), but I should note one, which is the rule
for loops:&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;[while(Q) do α done]P↔[if(Q) then α else pass endif;while(Q) do α done]P[\texttt{while}(Q)\ \texttt{do}\ \alpha\ \texttt{done}]P \leftrightarrow [\texttt{if}(Q)\ \texttt{then}\ \alpha\ \texttt{else}\ \texttt{pass}\ \texttt{endif};\texttt{while}(Q)\ \texttt{do}\ \alpha\ \texttt{done}]P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;while&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;done&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;↔&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;else&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;pass&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;while&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Q&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;done&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;yeah um there’s a bit of infinite recursion here. One way to handle this is by
giving up and pursuing a different area of computer science, since this is
again equivalent to the halting problem. Another way is to unroll the loop for
“enough iterations” and call it a day. We take the latter approach.&lt;/p&gt;
&lt;p&gt;With all these rules to turn box modalities into regular formulae, we can just
plug that resulting formula into &lt;a href=&quot;https://github.com/Z3Prover/z3&quot;&gt;Z3&lt;/a&gt; and bask
in the glory of modern computation. Hooray for automated theorem provers!&lt;/p&gt;
&lt;h3&gt;Program Instrumentation&lt;/h3&gt;
&lt;p&gt;So now we have a tool to help us reason about a condition at the end of a
program, but safety properties can be violated at any time in our program. How
can we reconcile this? Simple: we &lt;em&gt;rewrite the program so that any operation
that could violate the property sets a marker that cannot be changed
afterwards&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Here is how we would do that for the &lt;a href=&quot;#tinyscript&quot;&gt;previously-shown program&lt;/a&gt;,
for the safety property &lt;code&gt;x &amp;gt; 0&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#violated := 0;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;x := i;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;if !(x &amp;gt; 0) then #violated := 1 else pass endif;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;while x &amp;lt; (i-i)-1 do&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    x := x + 1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if !(x &amp;gt; 0) then #violated := 1 else pass endif&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’ve instrumented every assignment to &lt;code&gt;x&lt;/code&gt; with a check afterwards to make sure
that it’s value doesn’t dip below zero.&lt;/p&gt;
&lt;p&gt;By the magic of “it’s really easy to recur over syntax trees”, doing this
instrumentation automatically is fairly simple if you’re clever. With this
method, proving the safety property becomes equivalent to proving
&lt;span&gt;&lt;span&gt;[f(α)](#violated=0)[f(\alpha)](\texttt{\#violated} = 0)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;#violated&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (where &lt;span&gt;&lt;span&gt;ff&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the instrumentation
function), which we have the tools for!&lt;/p&gt;
&lt;p&gt;All the problems in the lab (bounded execution, no unused variables, taint
analysis w/o implicit flows) are meant to be solved using this strategy. If you
have some time and are curious about this, definitely check it out! &lt;a href=&quot;https://github.com/15316-cmu/lab1-2022&quot;&gt;It’s free
online&lt;/a&gt; and the writeup there is &lt;em&gt;much&lt;/em&gt;
better than what I could explain here.&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Unless, of course, you’ve taken this course before &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;like a set, “but better” &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Assignments to variables at each step in the program &lt;a href=&quot;#user-content-fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider: a program that does something unsafe only after (safely)
determining if a passed-in program terminates. &lt;a href=&quot;#user-content-fnref-4&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>projects</category><category>CMU</category></item><item><title>Photography Page Is Up!</title><link>https://www.hazelduvall.dev/blog/posts/2023-01-04-photography-page-is-up.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2023-01-04-photography-page-is-up.html</guid><description>In which I provide a link to my new showcase of photos that I took this last fall semester in school for a class, Digital Photography I, taught by Dylan Vitone.</description><pubDate>Wed, 04 Jan 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello 2023 I have some big news!! It took a bit longer than I thought but I finally finished the section of my website dedicated to photography.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;/photography.html&quot;&gt;Photography&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;^^^ click that above link to go to it. I worked pretty hard on these photos during the semester and learned a &lt;em&gt;ton&lt;/em&gt; and I would be very honored if you would take a look at them :)&lt;/p&gt;
&lt;p&gt;Oh but do be warned, there is approximately 0 optimization on these so each page is like 100MB or more, make sure you have a good internet connection before trying to load. This is also the part of the website I was complaining was hard in my previous post, turns out component-like things like “extra metadata per photo displayed in a common format” is harder than anticipated.&lt;/p&gt;
&lt;p&gt;That’s it for now, hopefully I have another post soon bye!!&lt;/p&gt;</content:encoded><category>Photography</category></item><item><title>I Don&apos;t Actually Like Hakyll That Much</title><link>https://www.hazelduvall.dev/blog/posts/2022-12-29-i-dont-actually-like-hakyll-that-much.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-12-29-i-dont-actually-like-hakyll-that-much.html</guid><description>In which I detail some problems I&apos;ve been having with the static site generator Hakyll, written in Haskell, that I&apos;ve been using to generate this site for quite some time now.</description><pubDate>Thu, 29 Dec 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Yeah, you heard me right. The static site generator I tried out on a whim so long ago and &lt;a href=&quot;/blog/tags/Hakyll.html&quot;&gt;struggled against for a while&lt;/a&gt; isn’t serving me that well. Let’s go over why I’m fed up with it and how we can do better.&lt;/p&gt;
&lt;h3&gt;The Good&lt;/h3&gt;
&lt;p&gt;So despite the complaining I’m going to do later in this blog post, Hakyll is honestly really nice. You probably get the best markdown engine anywhere, Pandoc, and for those that &lt;em&gt;really&lt;/em&gt; want to spice their text markup experience they have the flexibility to do so with custom plugins&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; and whatnot. It’s also really good at being flexible in &lt;em&gt;how&lt;/em&gt; you structure your site, once you write all the rules necessary for it.&lt;/p&gt;
&lt;h3&gt;The Bad: Haskell&lt;/h3&gt;
&lt;p&gt;I have not invested nearly enough time into having a good Haskell setup. This could be partly due to the fact that “good Haskell setups” are hard to come by and require deep knowledge of build systems, mostly just found at large companies and even then it’s likely in constant breakage&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. I had this on &lt;a href=&quot;https://docs.haskellstack.org/en/stable/&quot;&gt;Stack&lt;/a&gt;, and have now moved to &lt;a href=&quot;https://github.com/Gabriella439/haskell-nix&quot;&gt;Nix&lt;/a&gt; in an attempt to get something that would be able to cache build artifacts for CI because &lt;em&gt;it takes a really long time to build everything from scratch&lt;/em&gt; even on my not-puny machine.&lt;/p&gt;
&lt;p&gt;Neither of these are perfect solutions. I do however now have a language server and code formatter set up so the dev experience isn’t as horrible as it was before and overall the language is kinda nice actually, it’s just that&lt;/p&gt;
&lt;h3&gt;The Ugly: Hakyll&lt;/h3&gt;
&lt;p&gt;As explained in some of my previous posts, Hakyll incremental rebuilds work via a pretty nifty dependency system. Unfortunately, tapping into that like I tried to do is &lt;em&gt;stupid hard&lt;/em&gt; so I wouldn’t recommend it.&lt;/p&gt;
&lt;p&gt;Full rebuilds are probably recommended anyways, because you’ll need to do one every time you rebuild your &lt;code&gt;site&lt;/code&gt; executable. Why would you need to rebuild your site executable you ask? Well, if any of the following happen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding a new page not already covered by a glob&lt;/li&gt;
&lt;li&gt;Adding/renaming “derived metadata” fields
&lt;ul&gt;
&lt;li&gt;That is, metadata not directly encoded into the file&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Adding a new template layer to a page/changing the name of a template
&lt;ul&gt;
&lt;li&gt;Template layers are effectively how you do “components”, so these may change a lot depending on your style&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, actually &lt;em&gt;doing&lt;/em&gt; components with Hakyll is a PITA. “Make an item with no route and then use a partially applied template to load those items from a &lt;code&gt;listField&lt;/code&gt;” statements dreamed up by the utterly deranged&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. After having used &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; and &lt;a href=&quot;https://svelte.dev/&quot;&gt;Svelte&lt;/a&gt; for another project and getting past the initial Javascript apprehension I actually really like their model a lot more. When making a page you can just drill down on the components + loops put in-line with the markup, rather than bouncing between your content folder, template folder, and hakyll rules, having to rebuild every time you edit the latter.&lt;/p&gt;
&lt;h3&gt;Will I Rewrite This Blog?&lt;/h3&gt;
&lt;p&gt;Maybe! I’ll definitely be using Astro if I do. Astro still supports markdown and is fairly flexible in how it can be structured so I hope that a conversion wouldn’t be too hard. I’d also like to not spend that much time on it and once this project is over I don’t foresee Hakyll taking this much maintenance and frustration for a while again, so maybe later.&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I’m using one for &lt;span&gt;&lt;span&gt;LaTeX\LaTeX&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;E&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;X&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; embedded as SVGs which in hindsight isn’t the best idea of accessibility but carrying on &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Just like C/C++! &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This is actually what I’m doing for another page on this website that I’ll make a post about soon. &lt;a href=&quot;#user-content-fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>Web</category><category>Hakyll</category></item><item><title>Fall 2022 Semester Is Over</title><link>https://www.hazelduvall.dev/blog/posts/2022-12-15-f22-semester-complete.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-12-15-f22-semester-complete.html</guid><pubDate>Thu, 15 Dec 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So. That’s it huh. Final final project turned in, gearing up for going back to see family over break, I made it through.&lt;/p&gt;
&lt;p&gt;In this post I’ll review each of the classes I took this semester and maybe some general thoughts on what spring will be like. Only ordering is lexicographic class number.&lt;/p&gt;
&lt;h3&gt;10-414: Deep Learning Algorithms And Implementation&lt;/h3&gt;
&lt;p&gt;Absolute &lt;strong&gt;banger&lt;/strong&gt; of the class. The two profs, &lt;a href=&quot;https://tqchen.com/&quot;&gt;Tianqui (TQ) Chen&lt;/a&gt; and &lt;a href=&quot;https://zicokolter.com/&quot;&gt;Zico Kotler&lt;/a&gt; were/are doing cutting-edge research, and even I &lt;em&gt;recognized their names from big papers&lt;/em&gt;. So already u know they’re gonna be dropping knowledge bombs.&lt;/p&gt;
&lt;p&gt;This was the second time this class was run, but it hardly showed. You wouldn’t be able to tell just from the lectures (&lt;em&gt;really&lt;/em&gt; good, both of them), just some rough edges in certain places in the labs but nothing that couldn’t be overcome.&lt;/p&gt;
&lt;p&gt;This class also ran as &lt;a href=&quot;https://dlsyscourse.org/&quot;&gt;as open online version&lt;/a&gt; with everything needed to complete the course public, which I think is super cool and really shows their commitment to open source.&lt;/p&gt;
&lt;h3&gt;18-349: Embedded Systems&lt;/h3&gt;
&lt;p&gt;“Mini-OS” is how I liked to refer to this class. Lab 4 especially (building a small kernel for the embedded hardware) was wayyyyy more tricky than it needed to be; debugging tools for that board were &lt;em&gt;awful&lt;/em&gt; (&lt;code&gt;gdb&lt;/code&gt; with hardly any breakpoint support, no trace recording, no printf since &lt;em&gt;that’s where the bugs come from&lt;/em&gt;). However, it was really fun to do all the labs in Rust, an unusual arrangement we got instructor permission for.&lt;/p&gt;
&lt;p&gt;The content was pretty interesting, lots of introductions to topics you have to care about when putting computers in systems that will interact with the real world. Shame some of the labs were so crazy it spoiled my opinion a little, otherwise I really enjoyed this class. Never had &lt;a href=&quot;https://www.andrew.cmu.edu/user/gkesden/&quot;&gt;Prof. Gregory Kesden&lt;/a&gt; before but I kinda get what the hype around him is, &lt;a href=&quot;https://engineering.cmu.edu/directory/bios/budnik-mark.html&quot;&gt;Prof. Mark Budnik&lt;/a&gt; was really nice too.&lt;/p&gt;
&lt;h3&gt;21-373: Algebraic Structures&lt;/h3&gt;
&lt;p&gt;Just a chill math class with &lt;a href=&quot;https://www.cmu.edu/math/people/faculty/statman.html&quot;&gt;Prof. Richard Statman&lt;/a&gt;. Turned out to be only homework-based, which I did not know going in but really liked!! Learned the theoretical basis for the &lt;a href=&quot;https://en.wikipedia.org/wiki/Fundamental_theorem_of_algebra&quot;&gt;Fundamental Theorem of Algebra&lt;/a&gt;, starting allllll the way from &lt;a href=&quot;https://en.wikipedia.org/wiki/Fundamental_theorem_of_algebra&quot;&gt;Groups&lt;/a&gt;. Sets me up well for understanding more theoretical stuff in the future.&lt;/p&gt;
&lt;h3&gt;62-142: Digital Photography I&lt;/h3&gt;
&lt;p&gt;So all the above classes are like exactly the type of tech classes I like to take, and I really enjoyed them. Yet, this humanities course with &lt;a href=&quot;https://www.dylanvitone.com/&quot;&gt;Prof. Dylan Vitone&lt;/a&gt; ended up being my favorite! Likely because it was very low-stress, and us students were just encouraged to have fun in it. The lectures were still very useful, learned a lot more about just how wide the world of photography really is, expanded my horizons for what pictures can be and look like.&lt;/p&gt;
&lt;p&gt;I should post some of my assignments here; fairly proud of them and they deserve a place to show them off, even if it means breaking my rule of “no photos of me on the internet”.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Other Activities&lt;/h2&gt;
&lt;h3&gt;TA for 15-316: Software Foundations of Security and Privacy&lt;/h3&gt;
&lt;p&gt;I really enjoyed this class with &lt;a href=&quot;https://www.cs.cmu.edu/~mfredrik/&quot;&gt;Prof. Matt Fredrikson&lt;/a&gt; last year, and was really excited to TA for it this time. All the content was just as cool as I remembered, and Prof. Fredrikson just as nice + caring.&lt;/p&gt;
&lt;p&gt;There were a couple big changes this year, that I played a little bit of a role in bringing about as part of course staff: there are two new labs, written from scratch (mostly by Prof. Fredrikson’s herculean efforts) and both of them are freely available online.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/15316-cmu/lab1-2022&quot;&gt;The first&lt;/a&gt; goes into one approach to formal verification (instrument a program, run a SAT solver on the instrumented program)concretely applied to a toy language, embedded into a Python DSL.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/15316-cmu/lab2-2022&quot;&gt;The second&lt;/a&gt; shows how to &lt;strong&gt;&lt;em&gt;build a simple theorem prover&lt;/em&gt;&lt;/strong&gt; and we have an entire Python DSL for proof trees. While the goal of this lab was to just apply simple tactics to manually prove certain statements, one student ended up writing a &lt;strong&gt;general theorem prover&lt;/strong&gt; for our language which I think is really cool. I plan on doing a blog post about this lab in more detail since I think it deserves more attention.&lt;/p&gt;
&lt;h3&gt;CMU AAC Officer&lt;/h3&gt;
&lt;p&gt;Not a whole lot to talk about yet. I’m running our fall zine (which I tried to participate in but then couldn’t complete…) which should be published before spring starts, and Secret Santa which has yet to start. Haven’t drawn nearly as much as I would’ve liked this semester…&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Looking Forward To Spring&lt;/h2&gt;
&lt;p&gt;As it turns out, I only needed one more class to graduate&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;! As such, next semester will be extremely light. I plan on auditing interesting classes anyways, but having the extra flexibility/less stress will be very nice.&lt;/p&gt;
&lt;p&gt;A couple classes fill this requirement, so I’ll need to decide between 15-462 Computer Graphics, 15-330 Computer Security, or 15-455 Undergraduate Complexity Theory. Kinda leaning toward the last one tbh, only because it’s something I can only get at CMU. Heard mixed things about 15-330 but overall Computer Security is something I’m already interested in so it can’t be that bad. Graphics less so but likely still interesting. Thanks to a generous drop/tuition adjustment deadline, I’ll have 2 weeks to choose once the semester starts, we’ll see how it goes!&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I could’ve taken that class &lt;em&gt;this&lt;/em&gt; semester and graduated early but I didn’t count units right and thought I needed another full semester anyways so I didn’t whoops &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>class review</category><category>CMU</category></item><item><title>First Job Secured!</title><link>https://www.hazelduvall.dev/blog/posts/2022-12-12-first-job-secured.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-12-12-first-job-secured.html</guid><pubDate>Mon, 12 Dec 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have some big news: just signed my first job offer!!!!!!!!!!&lt;/p&gt;
&lt;h3&gt;Congrats! Where Are You Going?&lt;/h3&gt;
&lt;p&gt;Starting this summer, I’ll be working for &lt;a href=&quot;https://ro.am/about&quot;&gt;Roam&lt;/a&gt;, a &lt;em&gt;very&lt;/em&gt; small startup, doing Software Engineering of sorts.&lt;/p&gt;
&lt;h4&gt;What Does Roam Do?&lt;/h4&gt;
&lt;p&gt;Best way I can think of describing it is “a tool that makes a remote office that works”. Basically, actual virtual presence without any weird VR stuff.&lt;/p&gt;
&lt;p&gt;I also wasn’t entirely convinced until I tried out their demo, and then I was hooked, really something you have to experience to believe.&lt;/p&gt;
&lt;h4&gt;How Did You Find Out About Them?&lt;/h4&gt;
&lt;p&gt;Professional Network. Super lucky to have already met one of their engineers and their CEO beforehand, and again lucky enough for my skills in “trying out just about anything computer” being a good fit for what they were looking for.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;And seriously, I’m super excited to be working here, lots of great engineers to learn from and never-ending stream of interesting projects ahead. Looking forward to the summer!&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Roam</category></item><item><title>What Makes Rust Amazing?</title><link>https://www.hazelduvall.dev/blog/posts/2022-10-27-what-makes-rust-different.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-10-27-what-makes-rust-different.html</guid><pubDate>Thu, 27 Oct 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been thinking about this for a while, and I think it’s finally time to put
these thoughts into a blog post. Will update this later to fill out missing
sections but right now I just gotta put these thoughts down while I have some
time.&lt;/p&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#references-and-ownership&quot;&gt;References and Ownership&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#lifetimes&quot;&gt;Lifetimes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#real-move-semantics&quot;&gt;Real Move Semantics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#good-defaults-and-good-tooling&quot;&gt;Good Defaults and Good Tooling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#culture-of-safety&quot;&gt;Culture of Safety&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#algebraic-datatypes&quot;&gt;Algebraic Datatypes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#traits-instead-of-objects&quot;&gt;Traits Instead of Objects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note I have organized these in decreasing importance, at least in my view.&lt;/p&gt;
&lt;h2&gt;References and Ownership&lt;/h2&gt;
&lt;p&gt;This is the &lt;strong&gt;&lt;em&gt;biggest&lt;/em&gt;&lt;/strong&gt; thing ever. Like the other stuff I mention later on
is really important too, but without this &lt;em&gt;you don’t have Rust&lt;/em&gt;, you have
something like Zig or D which while still very good, simply just can’t provide
the same guarantees that Rust does in terms of memory safety.&lt;/p&gt;
&lt;p&gt;A simple explanation of references in Rust: there are two types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;T&lt;/code&gt;, an immutable a.k.a. shared reference&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;mut T&lt;/code&gt;, a mutable a.k.a. exclusive reference&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Coming from C++, the analogues are &lt;code&gt;const T&amp;amp;&lt;/code&gt; and &lt;code&gt;T&amp;amp;&lt;/code&gt;, and coming from pretty
much any other language the analogues are… kind of nothing. If you have a
reference to an object in Python, Java, Javascript, Go, etc., it’s a mutable
one, with kind of um no guarantees around really really classic problems like
thread safety and mutable aliasing.&lt;/p&gt;
&lt;p&gt;A classic example of mutable aliasing, a.k.a reference invalidation, is the
following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &amp;lt;vector&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; argc&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;char**&lt;/span&gt;&lt;span&gt; argv&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // Create a vector&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    std::vector&lt;/span&gt;&lt;span&gt;&amp;lt;int&amp;gt;&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // Get a reference to the second element in the vector&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; auto&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    std::cout &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; std::endl;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // Mutate the vector, invalidating `y`&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    x.&lt;/span&gt;&lt;span&gt;push_back&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    std::cout &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; std::endl;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // ***Insta-UB***&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    std::cout &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; std::endl;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The funny thing, the absolutely hilarious thing is that, at the time of this
writing, no modern C++ compiler (gcc, clang, MSVC) catches this in their
standard compilation pass, even with all warnings enabled. The equivalent Rust
code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;fn&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    let&lt;/span&gt;&lt;span&gt; mut&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; vec!&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    let&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;x[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;{}&quot;&lt;/span&gt;&lt;span&gt;, y);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    x&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;{}&quot;&lt;/span&gt;&lt;span&gt;, x[&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;{}&quot;&lt;/span&gt;&lt;span&gt;, y);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;shows a very readable error messages explaining exactly how You Messed Up:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; --&amp;gt; src/main.rs:5:5&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  |&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;3 |     let y = &amp;amp;x[1];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  |              - immutable borrow occurs here&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;4 |     println!(&quot;{}&quot;, y);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;5 |     x.push(5);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  |     ^^^^^^^^^ mutable borrow occurs here&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;6 |     println!(&quot;{}&quot;, x[4]);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;7 |     println!(&quot;{}&quot;, y);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  |                    - immutable borrow later used here&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;For more information about this error, try `rustc --explain E0502`.&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;error: could not compile `playground` due to previous error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is huge and prevents whole classes of memory errors simply by enforcing
mutation to only be done by one “section” of code at a time.&lt;/p&gt;
&lt;h3&gt;Lifetimes&lt;/h3&gt;
&lt;p&gt;How this gets enforced is with lifetimes. A lifetime can be thought of as “how
long a reference is good for”. In the above example, we got an error because we
had a shared reference’s lifetime overlap with that of an exclusive reference.&lt;/p&gt;
&lt;p&gt;Lifetimes are also useful because the maximum amount of time a lifetime can be
valid for is the lifespan of an object, from when it is created (think
&lt;code&gt;malloc&lt;/code&gt;, but you can also have stack-only objects) to when it is dropped
(think &lt;code&gt;free&lt;/code&gt; or popping the stack frame).&lt;/p&gt;
&lt;h3&gt;Real Move Semantics&lt;/h3&gt;
&lt;p&gt;Ownership is the other mechanism that makes this possible. I distinguish Rust’s
ownership and move semantics from C++‘s icky thing where a &quot;&quot;&quot;moved&quot;&quot;&quot; object
is still valid but &quot;&quot;&quot;empty&quot;&quot;&quot; somehow because this is the Real Deal; once you
move a Value (data in memory) out of a Variable (label in the program), that
Variable is no longer valid. To even do a move in the first place, the compiler
must guarantee that there are &lt;em&gt;no outstanding references to that variable&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This mechanism allows the compiler to &lt;strong&gt;automatically insert calls to drop
values&lt;/strong&gt; when it detects a variable with ownership cannot possibly be used
again. Again, this entire system is just a really neat way for the compiler to
statically guarantee exclusive mutation of objects, which is much more
complicated but just as important as doing bounds checks on all accesses.&lt;/p&gt;
&lt;p&gt;TODO: explain this better&lt;/p&gt;
&lt;h2&gt;Good Defaults and Good Tooling&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2&gt;Culture of Safety&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2&gt;Algebraic Datatypes&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2&gt;Traits Instead of Objects&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;So yeah sorry it’s unfinished and a bit rambly, I promise I’ll get around to
the rest of it eventually, at some point, later idk&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Identity, Pt. 2</title><link>https://www.hazelduvall.dev/blog/posts/2022-10-20-identity-pt2.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-10-20-identity-pt2.html</guid><pubDate>Thu, 20 Oct 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So maybe you’ve read my &lt;a href=&quot;./2020-11-20-online-identity.html&quot;&gt;other post about this from way
back&lt;/a&gt;, or maybe not, and in either case I
think it deserves an update. TL;DR I’ve used an alternate name online for so
long that it feels like another persona.&lt;/p&gt;
&lt;h3&gt;This is still going on huh&lt;/h3&gt;
&lt;p&gt;Yeah I don’t know if I was or wasn’t expecting it at the time but it’s been
almost 2 years of this equilibrium, and I think at this point it’s safe to say
it will probably continue indefinitely.&lt;/p&gt;
&lt;h3&gt;Do u have any idea why&lt;/h3&gt;
&lt;p&gt;I have two main hypotheses for why this is happening:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Internet Escapism
&lt;ul&gt;
&lt;li&gt;factors mentioned in the previous post, i.e. it’s freeing to be less on-edge
about how I’m presenting myself at all times&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I’m Built Different
&lt;ul&gt;
&lt;li&gt;this means whatever you think it means&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Are you going to connect these identities anytime soon?&lt;/h3&gt;
&lt;p&gt;Highly unlikely! In any case, through my involvement in
&lt;a href=&quot;https://www.cmuaac.com/projects&quot;&gt;AAC&lt;/a&gt;, it’s kinda already happened (because I
was careless)! It’s still tricky enough to connect the two, and I’d like to keep
it that way for now.&lt;/p&gt;
&lt;h2&gt;So what’s the “update”?&lt;/h2&gt;
&lt;p&gt;The main thing that’s changed is I’m much more invested in this alternate
identity. I have a separate website, more projects under the other GitHub
account, more social media profiles with that handle, more art, etc. Some people
I became friends with online refer to me by that name, in public, because that’s
just who they know me as.&lt;/p&gt;
&lt;p&gt;Another more recent change, and the thing which set off this post, is that I’m
really starting to explore what this means with other people, now that there
&lt;em&gt;are&lt;/em&gt; enough people who know both identities and therefore know my conundrum. If
you’re one of those people, and you’re reading this blog post, hi!&lt;/p&gt;
&lt;p&gt;This is all still new for me, but in the meantime, I’ll keep doing my same ‘ol
same ‘ol, being the best person I can be. Hope you’re doing so too, see you next
time!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>TA-ing</title><link>https://www.hazelduvall.dev/blog/posts/2022-10-19-taing.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-10-19-taing.html</guid><pubDate>Wed, 19 Oct 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This semester, I’m a TA for &lt;a href=&quot;https://15316-cmu.github.io/2022/index.html&quot;&gt;15-316, Software Foundations of Security and
Privacy&lt;/a&gt; taught by &lt;a href=&quot;https://www.cs.cmu.edu/~mfredrik/&quot;&gt;Matt
Fredrikson&lt;/a&gt;, who’s just an absolutely
phenomenal professor.&lt;/p&gt;
&lt;p&gt;While I have taught the &lt;a href=&quot;https://rust-stuco.github.io/&quot;&gt;Rust StuCo&lt;/a&gt; at CMU for
a 2nd semester now, there are a couple of new duties involved in TA-ing that
I’d like to give thoughts on.&lt;/p&gt;
&lt;h2&gt;Creating Homeworks&lt;/h2&gt;
&lt;p&gt;I am not very good at this (the Rust StuCo has had only around 2 “successful”
homeworks in its run so far). Fortunately, Prof. Fredrikson is &lt;em&gt;very&lt;/em&gt; good at
this, and has a bunch of material to draw from already having taught this
course a couple times before. He does most of the writeups, and the other TAs
help come up with most of the questions, but I &lt;em&gt;did&lt;/em&gt; help create a lot of the
infrastructure for a completely-new Lab 1 this semester, so that was fun, and
also a lot of time since I was learning things as I went along.&lt;/p&gt;
&lt;h2&gt;Grading&lt;/h2&gt;
&lt;p&gt;This part was less strenuous than I thought. We divide up the workload pretty
evenly, and I’ve found some good gaps in my schedule where I can just plow
through all 60 students once I get into a groove. As a student taking this
course, I thought my answers were very clever and unique, and now I realize
everyone here is like that, which is good since that means the vast majority of
them are correct.&lt;/p&gt;
&lt;h2&gt;Holding Office Hours&lt;/h2&gt;
&lt;p&gt;This part is the most interesting part of the job in my view. I get to interact
with students directly and try to get them to understand new subjects,
something I already had a bit of experience doing from tutoring at CMU. The
first couple weeks were extremely hectic, but now it seems people are coming
less, I think because there’s less work? I’m not entirely sure, here’s hoping
people come in more for this next lab…&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;In conclusion, TA-ing is a very enjoyable experience, especially since I’m
getting paid pretty OK for how much I’m putting in hourly. The professor is
nice, the students are smart, and the content is just good stuff that I can get
excited about.&lt;/p&gt;
&lt;p&gt;Also &lt;strong&gt;I’m back baby&lt;/strong&gt;, post hiatus over! Maybe! I’m still more active on other
platforms but I thought I might as well put something out here while I’m on
Fall Break since otherwise I just won’t do it!&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>A Strong Defense of Copyright</title><link>https://www.hazelduvall.dev/blog/posts/2022-07-04-a-strong-defense-of-copyright.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-07-04-a-strong-defense-of-copyright.html</guid><description>In which a friend and I have a discussion about how modern copyright has been affected by various forms of piracy and I become slowly convinced it may actually be bad</description><pubDate>Mon, 04 Jul 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;First this I want to note is this is &lt;i&gt;not&lt;/i&gt; just my writing: this is a discussion my friend and I have a discussion about how modern copyright has been affected by various forms of piracy. I thought it was really interesting and got permission to post it here under a pseudonym, Corporate Shill (CS). I’ve distinguished between their words (in green, the color of Money) and mine (in an innocent blue).&lt;/p&gt;

&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Question from watching too much youtube: I’ve noticed that VPN ads have shifted
from security&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; to talking about how British Netflix has different shows.&lt;/p&gt;
&lt;p&gt;I assume the regional differences are due to license agreements with the rights
holders. How long until streaming services are compelled to take better steps
to confirm their client location, or until “choose your server country” VPNs
are targeted as a means of subverting restrictions or something?&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;That’s already happened, there was this evil blog post about how Amazon was
partnering with a company to do exactly that (block VPN users)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/geocomply/status/1522249780675551234&quot;&gt;https://twitter.com/geocomply/status/1522249780675551234&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GeoComply (@GeoComply) Millions of U.S. adults use VPNs to illegally access
streaming services in other countries. But you can easily block content pirates
with GeoGuard VPN and proxy detection via @aws @cloudfront.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The original tweet and blog post was deleted, but there’s a backup on
archive.org:
&lt;a href=&quot;https://web.archive.org/web/20220505221032/https://aws.amazon.com/blogs/media/blocking-illegal-viewers-from-streaming-services/&quot;&gt;https://web.archive.org/web/20220505221032/https://aws.amazon.com/blogs/media/blocking-illegal-viewers-from-streaming-services/&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I love all the replies saying if you block this piracy they’ll do more explicit
piracy.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I mean they (the users) are literally still paying for the content! And I get
that licensing is a mess but ya to me this technology seems like revenue-losing
only.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Well they’re &lt;em&gt;not&lt;/em&gt; paying for the content, they’re paying for different
content, deciding what they think they should be paying for, and gaining access
by force.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;“Different content” well sorry if I can’t control where I live…&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;The streaming service probably does better overall from a larger effective
library, but I can’t imagine rights holders are happy to be paid for one thing
while providing another.&lt;/p&gt;
&lt;p&gt;You can choose what to buy and not buy, or instead choose something not for
sale (on alternative platforms, individual sale, rental, etc). There are
arguments about pirating things not available for legitimate sale and whether
the region based licensing makes sense, but given the situation I don’t think
blocking misuse is improper.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;“Paid for one thing while providing another” I can’t pretend to understand how
finances work but I can’t imagine how this would put licensers in a bad spot at
all; like they aren’t actively providing anything.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;A better way to go about this could be to bind location to account and limit
how often it can change, idk why they don’t.&lt;/p&gt;
&lt;p&gt;To respond to “not actively providing anything”, they (studios) have an up
front cost to produce a piece of media, which in exchange they get copyright to
the product. Maybe they want to sell to Netflix in the UK, but can get a good
deal in the US with a particular TV channel. Netflix pays less than a worldwide
license, (while the content is still available worldwide through VPNs), so the
rights holder gets less money, even assuming the US market is still fully
available.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Still not sure why the rightsholder didn’t go for the thing that would make
them the most money in the first place?&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;The actual financial relationships are weird, it’s like “can this company
continue to fund this studio under the assumption that they can produce
products that on average over their lifetime can produce a profit?”, lots of
lag time and middlemen involved.&lt;/p&gt;
&lt;p&gt;In the scenario I described, someone is willing to pay a premium rate, but only
in a certain region; that’s the US TV channel operating in a single country
that wants an exclusive show to compete with regional and global channels and
services. The buyer (Netflix) doesn’t want a worldwide license because of
language and broadcast regulations and transmission licenses and budget and
marketing scale or any number of possibilities, but the seller still wants to
access other regions that don’t interfere.&lt;/p&gt;
&lt;p&gt;idk how the separate netflixes and all work, I would assume they’re all a
single interest, but as long as there are regional players in the market, I can
imagine regional contracts making sense.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I now get why they would sell to a single streaming region (actually clears up
a lot of my confusion, thanks), but still don’t see how region spoofing eats
into these profits?&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;In the case where there is a legitimate alternative delivery, you are
circumventing that.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Unless the legitimate alternate delivery is another pay-per-view streaming
service, hasn’t the money has already been made? Like advertisers already paid
for ad slots based on average ratings and all.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;In my example the TV channel gets less than they paid for and Netflix gets
more.&lt;/p&gt;
&lt;p&gt;The rights holder gets the same for completed sales but loses trust in future
deals.&lt;/p&gt;
&lt;p&gt;Also think about it: where do the average ratings come from? :P&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;No clue, probably the cable box keeps track?&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I mean, they come from past statistics. By changing present statistics, you
change future averages.&lt;/p&gt;
&lt;p&gt;It’s another point of lag, but the effect still happens eventually.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Ah! That is true.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;The next season comes around, and the US TV channel can’t trust the studio’s
exclusivity contract not to be circumvented by VPN users and made worthless,
advertisers can’t expect the old amount of impressions, the parent company of
the studio (if one exists) can’t expect licenses of future products to be as
valuable.&lt;/p&gt;
&lt;p&gt;I don’t really like artificial exclusivity of media in general, but going
around it seems to just concentrate success in the streaming services that have
the weakest detection.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Just like capitalism intended 😤&lt;/p&gt;
&lt;p&gt;That was a good explanation of why artificial exclusivity can be helpful for
studio longevity, but on moral grounds it feels weird ya&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Circumvention doesn’t feel like a functional way of influencing the change you
actually want, just a short term financial imbalance until streaming services
change or stop getting sold.&lt;/p&gt;
&lt;p&gt;Yeah if we’re just going moral as a consumer, there’s also a stance that you
can steal from any big company doing well 😜. Most of my Disney lately has been
basically pirated, thinking about it but I’ve also watched a lot less since
that habit started, and I probably would watch new stuff in theaters if the
situation was right.&lt;/p&gt;
&lt;p&gt;“What are your crimes? comment below with your full name and address”&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Hello I torrent a lot&lt;/p&gt;
&lt;p&gt;of Linux installers 😎&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;:ooooo&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
 also question: do you mind if I
put our discussion text on my blog? appropriately attributed of course
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;As an “Anonymized Corporate Shill”; feel free, but I have no research or
numbers or anything behind this, it’s just a logical sequence that I think
would exist and explain what we see.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I do like logical sequences and also the existing stuff has no rigor so it’s
thematic :P&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;heck yeah&lt;/p&gt;
&lt;p&gt;Also fun piracy regionality subject I see frequently: arcade games&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Round 1’s “This machine should not be distributed outside Japan” lmao&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Lots of stuff is not even sold, individuals may not have operators in their
local area, and versions/games may go out of date and no longer have legitimate
purchase options for that exact product. It’s a breeding ground for illegal
piracy.&lt;/p&gt;
&lt;p&gt;Oh yeah they’re also full of licensed content lmao I still never figured out
how that works&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Maybe small enough market that it doesn’t have an impact on the bigger
licensing picture? And again the “not legally available” just creates new
(illegal resale) markets.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Like, Konami networking is by special contract with R1&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; (and D&amp;amp;B&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; to a
lesser extent), and on a technical level may work as an extension of Japan or
its own region.&lt;/p&gt;
&lt;p&gt;There’s also the question that I think often gets ignored about loss of arcade
machine sales. Maybe Pop’n Music 4 isn’t run because of newer versions
existing, or Museca being shut down entirely, but there are other experiences
like them.&lt;/p&gt;
&lt;p&gt;If you weren’t playing Chuni&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; on data, at home, for free, whenever you
wanted, you might be making choices between steam offerings and local arcade
options, or even the new home game versions from Konami.&lt;/p&gt;
&lt;p&gt;The standard for an “old” game in the community tends to be between 6 months
and a year, with game data being released when fairly similar games are still
being sold and operated.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;WOW that’s fast turnover. Does this mean resale eats more or less into profits
compared to a longer release cycle?&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;TODO: reword the following: This common commitment to “n-1”, i.e. releasing
full unlock updates for versions at least 1 behind current may work for those
who want the latest features now, but honestly getting game updates with full
3rd party server support and bonus features on a 6 month delay is insane.&lt;/p&gt;
&lt;p&gt;Wacca is still live for a bit to my knowledge, but the community is already
deep into making a version compiling all versions, custom chart maker, etc.&lt;/p&gt;
&lt;p&gt;This is really confusing because we again have this studio/provider/consumer
structure like with the video content but also there’s custom physical
hardware, there are live service elements, the consumer payment is pay per view
and revshared between publisher and operator. Konami actually charges the
arcade 15¢ per credit or something, I think Sega sells it up front but it’s the
same model.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Oh wow! So resales really would directly impact their bottom line huh unless
there’s some DRM forcing this payment to Konami somehow.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I think there is also a monthly fee for the live service and updates.&lt;/p&gt;
&lt;p&gt;Yeah so online features are a big thing, some games refuse to boot without a
server connection, others have limited features and severely limited song
selection as well as no access to unlocks and player save data. Operating
legitimately during the life of the live service is poor if not impossible. At
end of life, I think offline patches/kits are common, but these often are not
the sum of everything that has been, taking away licensed pop music and
whatever else they decide.&lt;/p&gt;
&lt;p&gt;For example, Chunithm went through a cabinet change to become Chunithm NEW,
with the old cabinets getting stuck on an offline patch of the latest version
pre-NEW, Paradise Lost. For R1 Japan, these cabinets have very low value,
especially if they’re getting the new ones, so they shipped them to America
where Chunithm was not previously operated by them. The song library is
severely gutted, and especially with the lack of save data, no enthusiast plays
it.&lt;/p&gt;
&lt;p&gt;This could create a pressure to acquire the new cabinets where there is demand,
or push players to the games that are available, but emulation is an option.
You can actually skip the cabinet part altogether and use a third party
controller to play on data.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Ah yeah that’s the type of DRM I figured.&lt;/p&gt;
&lt;p&gt;Emulation just works by ripping the data as it goes over the network and
parsing it in a separate machine?&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Off the drive mainly, but third party servers are made too. The game program is
modified to add back in songs whose licenses lapsed, subvert online checks,
etc.&lt;/p&gt;
&lt;p&gt;There are a lot of capital costs, secondary markets, tertiary markets, and
copyright that make everything complex and slow moving. However, I would assert
that emulation and modification has set up a condition that would make a
legitimate entry to the US market less successful. Like, maybe people will be
moral and stop the frequent dumps if access were expanded, and additional
interest will have been generated, but it just seems like too much uncertainty
for the publisher to deal with.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Apple shows you can push the jailbreak game pretty far, seems like this is
still lax at the moment.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Oh boy you have no idea: the encryption, the VPN routers, the multiple types of
security dongles, it’s clear that they have responded to activity multiple
times lol&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Ah! Nevermind that is pretty advanced.&lt;/p&gt;
&lt;p&gt;Ya it’s a bit unfortunate that there is enough hype to make it profitable, but
now they’re competing against free which is just impossible.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Yeah, and especially if someone bought a controller instead of going to a
public cab if you got the new &lt;span&gt;&lt;span&gt;400chunicontroller(probablyexpensivetoshiptoo),andthenNEWcameout5minutesfromyou,wouldyoureallyditchyourhomedeviceandpay400 chuni controller (probably expensive to ship
too), and then NEW came out 5 minutes from you, would you _really_ ditch your
home device and pay &lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;400&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;ni&lt;/span&gt;&lt;span&gt;co&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;er&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;bab&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;os&lt;/span&gt;&lt;span&gt;hi&lt;/span&gt;&lt;span&gt;pt&lt;/span&gt;&lt;span&gt;oo&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;an&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;E&lt;/span&gt;&lt;span&gt;W&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;am&lt;/span&gt;&lt;span&gt;eo&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;es&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;w&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;ce&lt;/span&gt;&lt;span&gt;an&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;1/play?&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;No way!&lt;/p&gt;
&lt;p&gt;I’m really starting to see why studio execs are so freaked out about piracy,
since it fundamentally changes the competitive landscape in a way that doesn’t
favor how they currently do business.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Also! There are simulators, free clones of games that don’t even require an
arcade machine or any hacking.&lt;/p&gt;
&lt;p&gt;I don’t know much about Clone Hero, Stepmania, and all the JP rhythm ones but
they seem more if not completely legal and then you can have community features
where people transcribe the stuff that comes out in the original game.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Oh really? I would’ve though the music licensing is still weird for that,
similar to Osu! Transcription also seems like a whole separate minefield wow.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/xXN9adKkmQE&quot;&gt;https://youtu.be/xXN9adKkmQE&lt;/a&gt; hey look DrumMania licensed song and level data
from the latest version available in DTXMania&lt;/p&gt;
&lt;p&gt;I’d actually argue in favor of the chart &lt;em&gt;videos&lt;/em&gt; generally, I feel like
they’re not a replacement and encourage exploration, interest, habit forming
the dancerush charts are taken from direct video output on legitimate cabs.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Sure, those are a very different experience than playing directly&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;But when it’s something playable on a sim that gives feedback and score… and
then from a rights perspective too, is the level design data copyrightable?&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I would think so yes&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I would think so too, but apparently like board game rules aren’t. Rules &lt;em&gt;text&lt;/em&gt;
may be, “mechanics” might be the word I heard.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Oh wow that’s interesting! Wonder what the distinction is/where the line is
drawn.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;You too can clone monopoly with unique art assets!&lt;/p&gt;
&lt;p&gt;But yeah, you get this weird place where all the parts are mostly copied, but
by different people with different scales and distribution methods. DTX&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; is
especially funny to me because the charts are usually very dependant on the
song, driven by the composition of the music. There is some room for
originality, but it’s totally possible that someone could make a chart for an
anime song that’s exactly the same as what Konami makes when they get to
licensing it.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;brb about to make a game whose rules depend on the order of every single word
in the rulebook so i can copyright the “mechanics”
too&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;So &lt;em&gt;is&lt;/em&gt; Konami the one that has the copyright there? Is it different if we
assume it was copied/inspired rather than derived from the original source?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/dwcb0YasK68&quot;&gt;https://youtu.be/dwcb0YasK68&lt;/a&gt; side note I enjoyed this one a good bit; note
the distribution method of the video being unlicensed music working over
YouTube’s special agreements :P&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I think this would fall under the cleanroom exceptions as understood by the
UNIX clone of MINIX and Google v Oracle&lt;sup&gt;&lt;a href=&quot;#user-content-fn-6&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;. Not entirely sure how that works
but iirc deriving the same thing from the same source idea is fine and not
copyright-infringing.&lt;/p&gt;
&lt;p&gt;Also YouTube music LMAO&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I remember Twitch and Facebook Live released music things at similar times&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;side side note every music platform is kinda inconsistent in their metadata
tagging/normalization&lt;/p&gt;
&lt;p&gt;Wait FB has music stuff?? I had no idea, wouldn’t be surprised tho their app is
huge&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Twitch had a whole thing where they made deals with tons of indie publishers
and added an integrated player and tried to create an environment that could
supply music with rights acquired like. It seems like a lot of effort and mone,
but people hated it because you couldn’t broadcast whatever pop music they
already wanted to listen to, also DMCA strikes.&lt;/p&gt;
&lt;p&gt;Meanwhile I think Facebook managed a YouTube-style deal with all the major
labels for their live platform, idk if there’s revshare or flat cuts or pay per
play or view or what but it’s like YouTube’s thing to me, sounds impossible,
probably nearly is, completely changes copyright in practice in a single space,
but the space is really big it kinda feels like there’s reform that was needed
to match a culture, but a private company got it done first, and thus lowered
the pressure people talk about adoption and economies of scale with youtube
competitors, but their rights agreements seem like a big part of what let’s you
just kinda upload whatever and have it usually be fine.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Oh yeah that Twitch thing!! dogdogHS still gets hit by mutes for playing from
Spotify playlists lol&lt;/p&gt;
&lt;p&gt;(also big agree on the impossibility of YouTube licensing agreement, probably
only works because they’re so big)&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;just on the vods tho?&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;ya&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Classic&lt;/p&gt;
&lt;p&gt;And another example, it’s not like it cuts music sales, people don’t go to his
stream for free Katy Perry. But also, he definitely doesn’t have the rights, is
aiming to entertain thousands for commercial gain, and presumably if he’s
playing it it enhances the show and thus makes him money&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;it does enhance the show and he is making bank&lt;/p&gt;
&lt;p&gt;Going back to YouTube, there are still DMCA strikes, but yeah most of the time
it’s just “hey there was music playing in this so I can’t make money off it
anymore also we’ll link to the original song” and the original video stays up
at least.&lt;/p&gt;
&lt;p&gt;Still not a great automated system if someone really does have rights or gets
hit with bogus claims or is using it under fair use.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Yeah, compared to mass piracy using your platform and delayed takedown notices
you might pass to users and compelled moderation it’s just done like it’s still
annoying and abused often, but you don’t have to be careful in order to
actually do things perfectly, and you don’t get usually hit with stuff later,
and the ads/link offer a middle ground solution with no custom (expensive?)
negotiation needed for every individual case.&lt;/p&gt;
&lt;p&gt;This has trailed off a lot lol but yeah, arts economics and rights are weird.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;lol yup may be my fault a little for all the random questions :P&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Oh I trailed down plenty of my own rabbit holes too&lt;/p&gt;
&lt;p&gt;I’m sure though even with other structures besides Capitalism, valuing art is a
hard thing to do&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Oh totally, I have no idea what would be a better alternative. Just the logical
conclusions of all this are wild&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I feel like when you see those government arts funds, they tend to have a
specific cultural goal in mind, and competition for their money. This couldmove
art out of the true culture and put value on presentation rather than
substance.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;what even is “true culture” anyways? anime feet THIS IS A JOKE&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Man of culture screenshot 🤣&lt;/p&gt;
&lt;p&gt;The market system does this too I guess, but it’s more random because the
people with the money aren’t all together :P&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;“People with the money aren’t all together” I have some bad news for you buddy&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I’m pretty sure there’s at least two groups, one of them is Disney, I’ll get
back to you on the other.&lt;/p&gt;
&lt;p&gt;Excited to buy my internet plan that comes bundled with cable tv, Disney+,
ESPN+, and whatever the third thing that’s still Disney is. I love choice.&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;IT’S HULU?! c’mon man…&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Hulu is also Disney??? that’s wild&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;I think it’s a comarketing thing, not a firm corporate structure relationship&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;“I can’t believe there are so many streaming services we have to pay for”
they’re all just Disney in different hats&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;figure&gt;&lt;/figure&gt;
&lt;p&gt;I do not have the rights to host this audio luckily I’m not please buy terraria
and the terraria soundtrack&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;Does TikTok? Does Discord? (Does my website linking to
Discord?)&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;CS:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;TikTok seems to viral for anything to be stopped; Discord seems to big to be
convinced to check&lt;/p&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hazel:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;
&lt;p&gt;And my website is too small to matter :P&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Ok that was it, sorry for the fizzling-out conclusion, thanks for reading all the way through hope you got something from it!&lt;/p&gt;

&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Good debunk video by Tom Scott: &lt;a href=&quot;https://www.youtube.com/watch?v=WVDQEoe6ZWY&quot;&gt;https://www.youtube.com/watch?v=WVDQEoe6ZWY&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Round 1, an arcade franchise in the US &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dave and Busters, a more well-known arcade franchise in the US &lt;a href=&quot;#user-content-fnref-3&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Short for &lt;a href=&quot;https://rhythm-cons.wiki/w/Chunithm&quot;&gt;Chunithm&lt;/a&gt;, an arcade
rythm game made by SEGA with open-source controllers &lt;a href=&quot;#user-content-fnref-4&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A rhythm game played with a lifelike electric drumset controller, where
the maps are like actually playing the drums to songs &lt;a href=&quot;#user-content-fnref-5&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don’t quote me on this I am not that good at computing legal history &lt;a href=&quot;#user-content-fnref-6&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>Writing</category></item><item><title>I Easily Get Lost In Cities</title><link>https://www.hazelduvall.dev/blog/posts/2022-06-17-i-easily-get-lost-in-cities.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-06-17-i-easily-get-lost-in-cities.html</guid><description>In which I detail my many misadventures getting lost in cities, both physically and metaphorically (mostly physically tbh).</description><pubDate>Fri, 17 Jun 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Whoops, forgot to actually push to the site, in case you couldn’t’ve guessed I
have been busy with my internship :P. Multiple post dump time!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I don’t know if you’ve heard, but New York City is a &lt;em&gt;big&lt;/em&gt; city. There are many
skyscrapers in Manhattan (like the central island thing containing Central
Park), all bunched up right against each other. The streets are long and
gridlike, and sometimes the sun sets exactly in-line with them so you get to
fully see all the dust in the air.&lt;/p&gt;
&lt;p&gt;At least where I’m staying, the streets are relatively clean, only a slight
amount of litter left out for the pidgeons. There have also only been a few
instances of crazy cars (in bike lanes, taking lefts into walk signs) and for
the most part because traffic moves so slowly anyways it’s pretty safe to be a
pedestrian in that regard.&lt;/p&gt;
&lt;h2&gt;Ok but like how do you get lost when the streets are all numbered?&lt;/h2&gt;
&lt;p&gt;Great question! I’m not entirely sure myself! I have a hypothesis:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I usually navigate in relation to (non-sun) landmarks, and the buildings all
occlude each other so that doesn’t work out.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Especially in Central Park, where there aren’t any marked roads you can see, it
was exceedingly easy for me to get lost. Not just once, but twice, I went out
for out-and-back runs there that ended up being out-and-out so I was double the
distance away… Learned my lesson there and now I run with Google Maps :P&lt;/p&gt;
&lt;p&gt;However, this is just my go-to navigation mechanism; surely attempting to
actually see what corner I’m on would help me get where I want to go?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I keep forgetting to orient myself at intersections, and have easily lost
orientation when taking multiple turns.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Especially with east-west streets, I’ve gone very long blocks in the wrong
direction before realizing it (yes I know I could’ve just looked for the
shorter north-south directions, but remember i am dum)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GPS/location services is &lt;em&gt;very&lt;/em&gt; spotty.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;… which doesn’t help with any of the above. I’ve heard it’s because GPS
signals reflect off buildings and the supposed Wi-Fi/Bluetooth MAC
address-based location services never really panned out like it promised to.&lt;/p&gt;
&lt;h2&gt;This Also Happened In Seattle&lt;/h2&gt;
&lt;p&gt;Oh yeah I should mention! The team I’m interning for had their calibration this
week in Seattle, so I was invited along for expensed business flights and hotel
:) Seattle is a neat city too (much smaller), had the best sushi of my life so
far there.&lt;/p&gt;
&lt;p&gt;The place near my hotel had street grids at 45 degree offsets from each other,
navigating which was a bit funky. Overall, I did a lot better than NYC (only
got lost once!), possibly because there were easier-to-use landmarks, and also
possibly because I’ve gotten more in the habit of navigating grids.&lt;/p&gt;
&lt;p&gt;I did not go up the Space Needle unfortunately, but I did go on the monorail
and light rail which were cool. Seeing it and hearing good things about Redmond
too is slightly making me consider west coast more… nah, east coast for lyfe
😤&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>I&apos;m In New York!</title><link>https://www.hazelduvall.dev/blog/posts/2022-05-31-im-in-new-york.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-05-31-im-in-new-york.html</guid><description>In which I detail the location of my internship this summer, recount the trip there, and offer some first thoughts on the city.</description><pubDate>Tue, 31 May 2022 12:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;How Did I Get Here&lt;/h2&gt;
&lt;p&gt;As I’ve mentioned &lt;a href=&quot;./2021-06-21-working-at-facebook.html&quot;&gt;previously&lt;/a&gt;, I’m
interning for Meta (formerly Facebook) this summer. There was a location
selection process, and I ended up choosing + getting assigned to New York City
(east coast baby!). Unlike last summer, which was entirely remote, this
internship is in-person so I’m getting flown out to, having housing provided
for, and paid to live in The Big Apple. (getting very spoiled i know)&lt;/p&gt;
&lt;h2&gt;How Was The Flight&lt;/h2&gt;
&lt;p&gt;Fairly standard, exiting LGA was pretty quick (although I’ve heard not great
things about getting in). Taking a Lyft from the airport wasn’t bad either.&lt;/p&gt;
&lt;h2&gt;Things I’m Looking Forward Too&lt;/h2&gt;
&lt;p&gt;I’ve never lived in as big of or as famous of a city as New York
(understandably, since few cities besides it can claim such a status). While
I’m here for a full 12 weeks, I’d like to be able to visit a good number of
museums, eat at some famous restaurants and some local restaurants, see a
Broadway show, and overall just enjoy all the other activities going on.&lt;/p&gt;
&lt;p&gt;The place I’m staying is right next to Central Park (2-3 blocks iirc) which is
pretty epic ngl, I’ll likely be spending a lot of time there. The “long-stay
hotel” also has some good amenities I hope to enjoy.&lt;/p&gt;
&lt;h2&gt;Things I’m Concerned About&lt;/h2&gt;
&lt;p&gt;It looks like I will need to commute to work, so taking the subway regularly
will be a first for me.&lt;/p&gt;
&lt;p&gt;Tech pickup also has a tight window, I think I can make it in time, they should
be fairly lenient regardless.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Overall, it’s pretty exciting to be in Da Big City, looking forward to my first
week!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 15</title><link>https://www.hazelduvall.dev/blog/posts/2022-05-30-qotd-15.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-05-30-qotd-15.html</guid><description>I&apos;m bringing back quotes of the day babyeeee! probably not tho</description><pubDate>Mon, 30 May 2022 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Wow, I haven’t seen one of those before!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TSA agent at DCA, commenting on my fightstick decorated with anime stickers&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;am i bringing these back actually? probably not lol&lt;/p&gt;</content:encoded><category>quote of the day</category></item><item><title>What I&apos;ve Been Up To Pre-Internship</title><link>https://www.hazelduvall.dev/blog/posts/2022-05-24-what-ive-been-up-to-pre-internship.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-05-24-what-ive-been-up-to-pre-internship.html</guid><description>In which I detail some half-finished projects I&apos;m moderately proud of and just generally give life updates</description><pubDate>Tue, 24 May 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s been &lt;em&gt;very&lt;/em&gt; nice to relax after that semester, I needed it.&lt;/p&gt;
&lt;p&gt;Due to large amounts of relaxing, hanging out with family, petting/walking my
remaining dog (R.I.P. Calvin, you are currently missed a lot and will continue
to be missed because you were the bestest and fluffiest and cutest dog), I
haven’t been doing a whole lot of computering. However, I do have a carnal need
for stimulation, and have satisfied my need by casually working on the
following projects:&lt;/p&gt;
&lt;h2&gt;UEFI Variable Writer for Windows, Written In Rust&lt;/h2&gt;
&lt;p&gt;I had worked on this a bit last summer, but it didn’t fully work for reasons I
wasn’t entirely clear on. Turns out I had everything correct (linking with
&lt;code&gt;windows-rs&lt;/code&gt; =&amp;gt; acquiring SYSTEM token for a thread =&amp;gt; calling the
&lt;code&gt;SetFirmwareEnvironmentVariableA&lt;/code&gt; function) except for not NULL-terminating the
string I wrote (Rust doesn’t do that for its strings, C needs it). So after
fixing that, it works!&lt;/p&gt;
&lt;p&gt;“But Hazel,” I hear you ask, “why did you want such an obscure tool in the first
place? Playing around with firmware variables is scary!” Well, my dear reader,
I wanted such a tool for my &lt;a href=&quot;./2019-07-15-operating-system-shopping-1-2.html&quot;&gt;Arch Linux
dual-boot&lt;/a&gt;, because
booting from Windows into Arch required mashing a key on boot which I often
forgot to do and then I would have to reboot all over again and it was slightly
annoying so I did what any good programmer would do and wrote a tool to
automate it.&lt;/p&gt;
&lt;p&gt;The bootloader I use,
&lt;a href=&quot;https://wiki.archlinux.org/title/Systemd-boot&quot;&gt;systemd-boot&lt;/a&gt; (which imo may
just be the best bootloader for UEFI btw), checks for a “LoaderEntryDefault”
UEFI variable and boots that configuration if it exists. This is very handy and
is how the included &lt;code&gt;bootctl&lt;/code&gt; tool changes the default boot without actually
modifying the config file living in the EFI system partition (very different
from GRUB).&lt;/p&gt;
&lt;p&gt;My goal, then, was to be able to write to that same variable, in the same
format, from Windows, so I could easily do something like &lt;code&gt;windows-bootctl set-default arch.conf&lt;/code&gt; and on the next reboot my computer would boot into Arch
without me having to spam any keys!&lt;/p&gt;
&lt;p&gt;So about the code: i uh put it under my &lt;a href=&quot;./2020-11-20-online-identity.html&quot;&gt;other
identity&lt;/a&gt; which has also been very active on
Twitter (and I posted lots of prototypes there so). If you’re very curious,
I’ve been informed it’s not impossible (quite feasible even) to link the two
with public online info, just please keep it a secret if u do find out.&lt;/p&gt;
&lt;h2&gt;OpenAFS For Windows&lt;/h2&gt;
&lt;p&gt;I’ve been on this since last year and I think the only reason I didn’t make a
post about it at the time is because I didn’t finish. I’m still not done, but
have made enough progress that I think I should share.&lt;/p&gt;
&lt;p&gt;Some motivation for why I wanted to do this: &lt;a href=&quot;https://www.cmu.edu/computing/services/comm-collab/collaboration/afs/index.html&quot;&gt;CMU uses
AFS&lt;/a&gt;
as a shared file system, useful for a lot of CS classes because your files will
be available from any machine you SSH into. Currently, I can download those
files with &lt;a href=&quot;https://winscp.net/eng/index.php&quot;&gt;WinSCP&lt;/a&gt; pretty easily, but it’s
slightly annoying to have to open the app and click “login” every time. Builds
of OpenAFS for Windows already exist, both
&lt;a href=&quot;https://www.openafs.org/frameless/windows.html&quot;&gt;official&lt;/a&gt; and
&lt;a href=&quot;https://www.auristor.com/openafs/client-installer/&quot;&gt;unofficial&lt;/a&gt; (unofficial
preferred since it backported a few security patches), but I have a compulsion
to stay on the bleeding edge so I thought I’d give it a shot myself.&lt;/p&gt;
&lt;p&gt;Oh boy was I in for a surprise. This is hands-down the gnarliest codebase I’ve
ever encountered. A succinct way to describe it is that the last big upgrade to
the code seems to be to support Windows 2000. There are still files that
manually load function pointers from external DLLs (via certain syscalls)
without relying on the OS. There were many &lt;code&gt;&amp;lt;stdint.h&amp;gt;&lt;/code&gt; headers missing,
&lt;code&gt;#define&lt;/code&gt;d names that conflicted with those in internal WDK headers, and an
ungodly number of compiler warnings.&lt;/p&gt;
&lt;p&gt;In the end, after 67 files changed, 4159 insertions(+), 2034 deletions(-) (most
of that in Visual Studio &lt;code&gt;.vcxproj&lt;/code&gt; and related files tbh (which I needed to
add since their driver build system was not longer supported past Windows 7)),
I was able to get all their files to build! However, that’s not the end of the
story: all of the executables complain about a “incorrect side-by-side
configuration” and the drivers don’t want to install since they’re not signed.&lt;/p&gt;
&lt;p&gt;I’m focusing on the driver issues first, since being able to develop drivers on
Windows seems more applicable outside of this one project, but uh that’s sort
of taking a while since Visual Studio isn’t cooperating (and
&lt;a href=&quot;https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debug-universal-drivers---step-by-step-lab--echo-kernel-mode-&quot;&gt;the smallest possible WinDbg setup&lt;/a&gt;
is very complex).&lt;/p&gt;
&lt;h2&gt;Doing Art&lt;/h2&gt;
&lt;p&gt;I’ve been voted in as Tech Chair for &lt;a href=&quot;https://www.cmuaac.com&quot;&gt;AAC&lt;/a&gt; for the
second year in a row! (I was the only one who ran for that position (but also
there were no votes of no confidence so that was nice)). Somewhat related to
that, I’ve been trying to do a lot more art, studying from Micheal Hampton’s
book &lt;strong&gt;Figure Drawing: Design and Invention&lt;/strong&gt;. I can see the improvement in my
sketches just after doing a few exercises; being able to “see” what the shapes
are helps a lot with recreating them in an image.&lt;/p&gt;
&lt;p&gt;I’ll be contributing to the club’s upcoming collaborative banner (past banners
&lt;a href=&quot;https://imgur.com/a/y07CpSn&quot;&gt;here&lt;/a&gt;, i was a part of both :)), and probably
participating in our internal ArtFight in August. Drawing is just fun and I’m
glad I can be part of this club even if I’m not at the same level :).&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Looking forward&lt;/h3&gt;
&lt;p&gt;This next week I’ll be doing more of the same, still mostly relaxing, and
ramping up prep for my internship at Meta, working with the Community App
Health Engineering team in New York City. I am not sure what the team does yet
and also not sure where I’ll be living but I’ve heard other people are in the
same spot so here’s hoping it’ll work out.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>The OS Semester</title><link>https://www.hazelduvall.dev/blog/posts/2022-05-11-the-os-semester.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2022-05-11-the-os-semester.html</guid><description>In which I recap how the Spring 2022 semester went for me, focusing on all the cool stuff that happened, particularly in the Operating Systems class at CMU</description><pubDate>Wed, 11 May 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wowza, that was quite the semester. A list of the classes I took, also the order
I’ll cover them in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;10-405 Machine Learning With Large Datasets&lt;/li&gt;
&lt;li&gt;17-200 Ethics And Policy Issues In Computing&lt;/li&gt;
&lt;li&gt;21-301 Combinatorics&lt;/li&gt;
&lt;li&gt;15-410 Operating System Design And Implementation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10-405&lt;/h2&gt;
&lt;p&gt;Taught by Prof. Virginia Smith, this class was an introduction into how you’d
actually construct machine learning systems to perform well at scale. “At
scale” usually meant “on multiple computers”, which is indeed a challenge due
to things like communication overhead. We started small, covering things like
distributed Linear Regression and distributed PCA, and ended with
state-of-the-art approaches to Neural Architecture search and Federated
Learning.&lt;/p&gt;
&lt;p&gt;Overall, I liked this class a lot. The lectures were very good and the
homeworks chill. One common complaint about homeworks that I share is that they
were sometimes &lt;em&gt;too&lt;/em&gt; structured; there was a lot of “fill in this function
signature that we’ve made for you already”. The later homeworks did a better
job of this, and I can understand why they did this in the first place (makes
grading easier and eases the learning curve for frameworks like Apache Spark
and Tensorflow).&lt;/p&gt;
&lt;p&gt;This class was within its unit count of 9hrs/week.&lt;/p&gt;
&lt;h2&gt;17-200&lt;/h2&gt;
&lt;p&gt;Co-taught by Prof. Michael Skirpan and Prof. Sarah Fox, this class was a very
practical overview of contemporary policy issues in computing and how to apply
ethical thinking to those. I really liked this compared to the previous ethics
class I took, which covered ethical frameworks in a more abstract term; getting
to learn about surveillance as “instrumentarian power”, unionization movements
in big tech, and dark patterns in UX felt much more real. This class humbled me
with the realization of just how much power is wielded by broken systems, but
also gave some concrete paths for improvement as future tech workers.&lt;/p&gt;
&lt;p&gt;This class fulfilled my writing requirement, and overall the weekly writing
assignments and writing midterm/final weren’t all that bad. I only wish I had
more time to work on the assignments (no fault of the class, just busy with all
other classes too) and was better at the writing process (mental block on
drafting + reviewing…).&lt;/p&gt;
&lt;p&gt;This class was within its unit count of 9hrs/week.&lt;/p&gt;
&lt;h2&gt;21-301&lt;/h2&gt;
&lt;p&gt;Taught by Prof. Irina Gheorghiciuc, this class covered some novel ways of, you
guessed it, counting things. It started off simple like “what a combination is”
and then quickly progressed to wild things like using functions and their
derivatives (whose coefficients of their Taylor polynomial are the things we
want to count) to do counting, then expanding on that to cool theorems like
Hands and Decks, Lagrangian Inversion, and Inclusion/Exclusion. Very cool to
know that &lt;span&gt;&lt;span&gt;u(x)=xϕ(u(x))u(x) = x\phi(u(x))&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; has a unique solution,&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;[xn]{u(x)}=1n[xn−1]{(ϕ(x))n}[x^n]\left\{u(x)\right\}=\frac{1}{n}[x^{n-1}]\left\{\left(\phi(x)\right)^n\right\}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Absolutely magic how this is proved :)&lt;/p&gt;
&lt;p&gt;I can see why all my math major friends meme about Irina’s lectures (very
unique and humorous style) and her tests (some problems are quite hard). I
really enjoyed this class; while I probably won’t get to use much directly
later on, it’s nice to keep my mathematical thinking sharp.&lt;/p&gt;
&lt;p&gt;This class was within its unit count of 9hrs/week.&lt;/p&gt;
&lt;h2&gt;15-410&lt;/h2&gt;
&lt;p&gt;Taught by Prof. Dave Eckhardt, this class covered &lt;em&gt;everything&lt;/em&gt; you need to know
about writing a simple UNIX-inspired OS kernel, and then some. x86 &lt;code&gt;cdecl&lt;/code&gt;
stack layout and calling convention, x86 memory model/atomic operations, x86
interrupts (traps, exceptions, faults, hardware), x86 segmentation, x86 virtual
memory mapping, how to structure a large software project, the thread/process
abstraction model (and how to implement it), concurrency problems like
deadlock, syscalls (and how to implement them), and more stuff that we didn’t
get around to implementing like filesystems, transactions, IPC/RPC,
paravirtualization, memory consistency, and the experimental CHERI
architecture. In case you couldn’t tell from the previous sentence, we wrote
our OS for the x86 architecture and got very familiar with its idiosyncrasies.
In the end, we had a lightly-featured (and working!!) kernel with a simple
threading library able to run some useful multithreaded programs with keyboard
input and console output.&lt;/p&gt;
&lt;p&gt;The class moved at a breakneck pace to cover all of these topics (which were
all covered in a lot of detail!); there was hardly a point in lecture where I
wasn’t moving my pencil. There was also hardly a day past the first week where
I wasn’t working on the OS project; a final &lt;code&gt;sloccount&lt;/code&gt; of the kernel showed
5000+ lines of mixed C and Assembly (however it counts that (and there was
probably more documentation than that too)).&lt;/p&gt;
&lt;p&gt;This class was &lt;em&gt;not&lt;/em&gt; within its unit count of 15hrs/week :) More like 25 I
think? Didn’t keep too close track, just estimating from the times I tended to
program every day.&lt;/p&gt;
&lt;h3&gt;15-410: It’s A Partner Class&lt;/h3&gt;
&lt;p&gt;For those familiar with 15-410, you may recall that it’s mainly a partner
class; 10 of the 14 weeks are spent working on projects with another person.&lt;/p&gt;
&lt;p&gt;This did not turn out well.&lt;/p&gt;
&lt;p&gt;I didn’t realize that people generally find OS partners before class starts, so
everyone I already knew in the class had already found someone by the time I
started looking. In a historic twist of fate, I talked to the person who always
sat next to me in the front row, who turned out also to not have a partner, and
we quickly made a group.&lt;/p&gt;
&lt;p&gt;Keep in mind, I had never even seen this person before this class. I had no
idea how this was going to go, but given the questions they asked in class (and
the fact they showed up to class at all) I was fairly optimistic.&lt;/p&gt;
&lt;p&gt;They turned out to have many issues. Mental health, physical health, &lt;strong&gt;and&lt;/strong&gt;
family issues, all in a negative feedback cycle. Naturally, this precluded
getting work done, often in week-long stretches during schedules where missing
a single day could be a bad setback.&lt;/p&gt;
&lt;p&gt;I ended up designing and implementing every single syscall, and every submodule
to support all those syscalls. They contributed some good code and helped walk
through design decisions (especially in the P2 and P4 projects before and after
the big P3 kernel), but overall I’m still a bit salty about the work
distribution even though nothing could really be done.&lt;/p&gt;
&lt;p&gt;The course staff knew about these issues and we were awarded generous (and very
necessary) late days. I’m (moderately) proud of what we turned in, but holy cow
I don’t want to crunch that hard ever again.&lt;/p&gt;
&lt;h2&gt;Random Other Stuff&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;OS sapped all my time and I couldn’t make many late-night or weekend Frisbee
practices this semester :(&lt;/li&gt;
&lt;li&gt;My knee is fully better by now though, been working out and going for runs
just fine&lt;/li&gt;
&lt;li&gt;I’ve been voted in as Tech Chair for &lt;a href=&quot;https://www.cmuaac.com&quot;&gt;AAC&lt;/a&gt; for the
second year in a row! Wow thank you!&lt;/li&gt;
&lt;li&gt;Speaking of, I’ll try to do more sketching practice this summer. I completed
Figuary again this year and have been using Hampton’s book a lot and I can
see the results (from just the parts I’ve read tho)&lt;/li&gt;
&lt;li&gt;StuCo thoughts coming soon! (when I finish “grading” the finals)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>class review</category><category>CMU</category></item><item><title>Wow, What A Year</title><link>https://www.hazelduvall.dev/blog/posts/2021-12-31-wow-what-a-year.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-12-31-wow-what-a-year.html</guid><description>In which I recap some highlights from 2021 and overall enjoy winter break</description><pubDate>Fri, 31 Dec 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;2021 was a year mainly full of one thing: COVID. From stunting last spring
semester to be entirely online (first time living alone!), to lessening in the
summer and fall, and now variants coming back with a vengance, the overall pace
of the year felt slowed down by the virus.&lt;/p&gt;
&lt;p&gt;It’s hard to believe this is the same year I &lt;a href=&quot;./2021-01-23-facestuff-1.html&quot;&gt;learned OpenGL and C++ to make a
simple demo&lt;/a&gt;, or &lt;a href=&quot;./2021-04-05-mile-time.html&quot;&gt;ran a 6-minute mile&lt;/a&gt;; those events feel
like so long ago (yes they were but still). Other big events were &lt;a href=&quot;./2021-05-19-housing-search-is-brutal-but-at-least-its-over.html&quot;&gt;renting my first apartment&lt;/a&gt;,
&lt;a href=&quot;./2021-06-21-working-at-facebook.html&quot;&gt;interning at facebook&lt;/a&gt;, and &lt;a href=&quot;./2021-08-15-so-i-have-a-pacemaker-now.html&quot;&gt;getting
sick with Lyme’s Disease&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Besides all the COVID variants, there was another huge event in 2021 for the
history books: the Jan 6 insurrection against Congress ratifying the
presidential election. Trump’s handling and encouragement of that mess
definetly deserved him getting kicked off all major social media platforms.&lt;/p&gt;
&lt;p&gt;With Biden as president, “normal” has been somewhat achieved: a Congress that
hardly passes any bills of import, and a constant dissatisfaction with the
executive branch for not making that happen. It depresses me how ineffective
the national government is, and all the state governments banning abortion and
mask mandates don’t help either. Count myself lucky to not be too affected
(yet).&lt;/p&gt;
&lt;p&gt;Anyways enough with the bad news from last year, what am I looking forward to
in 2022? Some main things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I’m teaching a &lt;a href=&quot;https://www.cmu.edu/stuco/&quot;&gt;StuCo&lt;/a&gt; on Rust alongside &lt;a href=&quot;https://github.com/kopecs&quot;&gt;Cooper
Pierce&lt;/a&gt; next semester! Very excited for this, we
both enjoy Rust alot and started this almost as a meme but now it’s a real
thing that 39 (!!) other students have signed up for. Hype 🦀&lt;/li&gt;
&lt;li&gt;I’m taking &lt;a href=&quot;https://www.cs.cmu.edu/~410/&quot;&gt;15-410 Operating Systems&lt;/a&gt; next
semester! This is “the big one”, all of the 15-4xx systems classes at CMU are
known to be very difficult but very rewarding in term of what you learn.
Due to the expected increased time commitment, I’ll need to stop tutoring
though, which is a bit of a bummer since I enjoyed it this semester. But! OS
awaits, and I can’t wait!&lt;/li&gt;
&lt;li&gt;Getting back to playing Ultimate Frisbee! It took all winter, but my knee is
finally healed after I busted it doing a heavy lift right after I was cured
of Lyme, having not exercised in a month. I’ve been doing other lifts and
track workouts since, and it’s held up fine so I can’t wait to actually
play. Hoping that practices aren’t scheduled at the same time as class
again…&lt;/li&gt;
&lt;li&gt;I’ll be interning at Facebook, now Meta again this summer! I got a return
offer and took it, love being able to skip interview season and relax! Again,
I’m still apprehensive about working for them given some of the relevations
that came out this year, but on the whole I expect it to be fine.&lt;/li&gt;
&lt;li&gt;I have no idea what next fall semester will be like!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s it for me this year, hope your 2021 was bearable and I’ll see you in
2022!&lt;/p&gt;</content:encoded><category>class review</category><category>CMU</category></item><item><title>Made it to Finals Week!</title><link>https://www.hazelduvall.dev/blog/posts/2021-12-04-made-it-to-finals-week.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-12-04-made-it-to-finals-week.html</guid><description>After another long hiatus caused by lots of school, I&apos;m back with another post! Feat. research and twitter reveal</description><pubDate>Sat, 04 Dec 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As I sit here, the day after a hectic final week of classes and 2 days before
finals week proper, I start to reflect on just how much has happened this Fall
2021 semester. I accepted Facebook’s return internship offer, signed a lease
for next year’s apartment, saw my family for Thanksgiving, achieved a 2-plate
bench, and besides that…&lt;/p&gt;
&lt;p&gt;Hm. I guess I have been focusing on school a bit too much. The past semesters
have been like this as well; I hardly have time to hang out with friends, let
alone work on cool projects.&lt;/p&gt;
&lt;p&gt;I’m probably also being impacted by burnout right now. Because no assignments
could be due the Monday or Tuesday after Thanksgiving, all assignments were
due on Wednesday, Thursday, and Friday this week. Thanks to not working over
break (which I needed), I had to grind hard this week (which I didn’t need).
In the end, I made it through, turned everything in while maintaining my usual
quality, but at the cost of just not wanting to work on anything for a while.&lt;/p&gt;
&lt;p&gt;There are still finals on Monday and Tuesday though, so I’m spending today to
just recover and will spend Sunday doing whatever review I need to do. These
aren’t finals I can just cruise through, so I am still a bit stressed about,
and more stress is the exact opposite of what I need right now.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Despite all of this, I actually do have something I’d like to show! My
&lt;a href=&quot;./2021-12-03-deep-learning-research-project.html&quot;&gt;Deep Learning Research
Project&lt;/a&gt;, which I’ve
back-dated to the day it was due. There’s more details in the post itself, go
check it out!&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>Deep Learning Research Project</title><link>https://www.hazelduvall.dev/blog/posts/2021-12-03-deep-learning-research-project.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-12-03-deep-learning-research-project.html</guid><description>My group&apos;s final paper for CMU&apos;s 10-417 Fall 2021 research project. We used seq2seq transformers to explore title generation from abstracts.</description><pubDate>Fri, 03 Dec 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This semester, my group and I at CMU did some simple research for 10-417,
Intermediate Deep Learning. By “group” I mean fellow undergraduates in the
class. &lt;strong&gt;You can view the paper &lt;a href=&quot;https://www.hazelduvall.dev/static/f21-10417-project.pdf&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Our project inspired by &lt;a href=&quot;https://www.kaggle.com/Cornell-University/arxiv&quot;&gt;the arXiv dataset on Kaggle&lt;/a&gt;,
specifically one of the tasks, “Title prediction by abstract”. That seemed
pretty cool, and a good opportunity to learn about modern NLP models, so we
dove right in.&lt;/p&gt;
&lt;p&gt;Looking back on our progress, I probably should’ve spent less time reading and
debugging frameworks that didn’t work, and more time training models. I read
a lot about Language Models, models that predict how likely a given piece of
text is to be non-gibberish, only to come to the conclusion they aren’t very
good at summarization anyways. Still, trying to understand them to the level
that I attempted to implement them was very helpful to understand the basis
behind a lot of other techniques; I got to see how everything “fit together” in
a sense.&lt;/p&gt;
&lt;p&gt;One of the main takeaways from the project was that this task is a lot harder
than it seemed! Many titles are pretty creative, not having an obvious relation
with the abstract or using non-standard lingustic constructs. Other titles were
able to be predicted a lot more easily, and on the whole there was a wide range
of prediction accuracy. Seeing predicted titles was humorous at times, I
wonder if I should set up a Twitter bot or something…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; &lt;a href=&quot;https://www.hazelduvall.dev/static/f21-10417-project.pdf&quot;&gt;paper here&lt;/a&gt;, didn’t get good results
but learned a lot.&lt;/p&gt;</content:encoded><category>projects</category><category>AI</category><category>CMU</category></item><item><title>Wait, How&apos;d I Miss Semptember?</title><link>https://www.hazelduvall.dev/blog/posts/2021-10-04-howd-i-miss-september.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-10-04-howd-i-miss-september.html</guid><description>I reminisce about the month during which I may have completely forgotten about my blog</description><pubDate>Mon, 04 Oct 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow, what a month. I’m back at college, and was very much immediately thrust
into all sorts of activities as school started. The rare occasion of 1)
remembering the blog and 2) having time to update it has finally come to pass,
so here we are: A List Of All Memorable Things That Have Happened&lt;/p&gt;
&lt;h2&gt;I Messed Up My Knee(s)&lt;/h2&gt;
&lt;p&gt;The first gym workout back. The &lt;strong&gt;&lt;em&gt;warm-up&lt;/em&gt;&lt;/strong&gt; set of squats. I went too low and
injured my left patellar tendon (the one on the front of the knee). Not knowing
the severity at the time, I rested it off for a week. Then went for a run and
messed it up again. Then waited another week to see a nurse who said “ya you
shouldn’t be doing anything rn kiddo”.&lt;/p&gt;
&lt;p&gt;As an added bonus, my right knee now has similar symptoms because any time I
needed to do a squat-like motion in daily life, I just did a single-leg squat
with it. So now both knees are out of comission for a while. This sucks a lot
because…&lt;/p&gt;
&lt;h2&gt;Frisbee Is Back&lt;/h2&gt;
&lt;p&gt;And I made the B team! I was hoping to make the A team this year, but injury
and also the fact that there are many people better than I means I’ll be on the
more relaxing team again. This isn’t a terrible thing, I just wish I wasn’t
injured so I could put more time into it.&lt;/p&gt;
&lt;h2&gt;I’m a Club Officer Now??&lt;/h2&gt;
&lt;p&gt;I forget if I’ve mentioned this before, but for Artist Alley Club, I am
officially the “Tech Chair” in charge of technical matters like organizing the
Google Drive and setting up bots in the Discord. Very chill, running the
activities is fun. Oh yeah here’s that art I promised earlier:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://www.hazelduvall.dev/static/summer21_zine_piece.png&quot; title=&quot;Wow look how cool that is!&quot; alt=&quot;Stylized view of an access road underneath a bridge between two CMU buildings&quot; /&gt;&lt;figcaption&gt;This is the piece I did for AAC&apos;s Summer 21 Zine&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2&gt;Looking For Research&lt;/h2&gt;
&lt;p&gt;If you are a professor I emailed while looking for research and you found this
blog, hi! Hope it isn’t too messy :)&lt;/p&gt;
&lt;p&gt;So basically, I have a return offer for Facebook next summer, but I would
prefer to do research at CMU if at all possible. I’m doing a research-ish
project for 10-417 this semester, and should be able to make time this Spring
to do research if things don’t work out for the summer.&lt;/p&gt;
&lt;h2&gt;I Am Still Bad At Fighting Games&lt;/h2&gt;
&lt;p&gt;I bought &lt;a href=&quot;https://www.dustloop.com/wiki/index.php?title=Guilty_Gear_-Strive-&quot;&gt;Guilty Gear Strive&lt;/a&gt;
for PC, and boy am I just getting my butt handed to me by other players. There
is a Fighting Game Community (FGC) at CMU, and when I showed up to a local I
was by far the worst player there. I really want to like these games, but man
is it fustrating to lose over and over and not really know what to do about it
besides “play more and maybe the instincts will come”.&lt;/p&gt;
&lt;h2&gt;Using a New Shell&lt;/h2&gt;
&lt;p&gt;I’m trying out &lt;a href=&quot;https://www.nushell.sh/&quot;&gt;Nu Shell&lt;/a&gt; on Windows as my default
shell, and so far it’s going pretty well. The only hiccup I’ve encountered so
far is that Python virtual environments don’t work too well in it, since they
rely on Batch files to set up environment variables and Nu isn’t compatible
with that. Other than that, it has good tab complete and simple Git
integration, worth seeing where it goes. I’m just happy to have another shell
rn lol&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Ok phew that was all the stuff I wanted to talk about. Sorry it’s a little too
self-centered, but I guess that’s what a blog is supposed to be anyways. Until
next time!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>OpenSSH and Kerberos</title><link>https://www.hazelduvall.dev/blog/posts/2021-08-25-openssh-and-kerberos.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-08-25-openssh-and-kerberos.html</guid><pubDate>Wed, 25 Aug 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, with the extra free time provided by being off the internship &amp;amp; not
allowed to exercise, I resumed my quest to sign into &lt;code&gt;unix.andrew.cmu.edu&lt;/code&gt;
without needing to enter my password every time.&lt;/p&gt;
&lt;p&gt;I had actually accomplished this in the past on Linux. I installed MIT Kerberos
with a package manager, copied the &lt;code&gt;/etc/krb5.conf&lt;/code&gt; file from the remote server,
signed in with &lt;code&gt;kinit&lt;/code&gt;, enabled using Kerberos with &lt;code&gt;GSSAPIAuthentication yes&lt;/code&gt;
and &lt;code&gt;GSSAPIDelegateCredentials yes&lt;/code&gt; for the server profile, and bam it worked.&lt;/p&gt;
&lt;p&gt;However, now I use Windows full-time, not even touching MSYS2, and want it to
work there as well. The steps look roughly the same, but it’s a bit more
involved.&lt;/p&gt;
&lt;h2&gt;Trying to work with Windows-native Kerberos&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR&lt;/em&gt;&lt;/strong&gt; it don’t work see the next section&lt;/p&gt;
&lt;p&gt;Windows actually has Kerberos support built-in! And, with a fairly recent
&lt;a href=&quot;https://github.com/PowerShell/openssh-portable/pull/360&quot;&gt;patch to OpenSSH that comes with Windows&lt;/a&gt;,
enabling GSSAPI for SSH will use that Kerberos (or other authentication using
the &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/win32/secauthn/sspi-kerberos-interoperability-with-gssapi&quot;&gt;Security Support Provider Interface&lt;/a&gt;).&lt;/p&gt;
&lt;h3&gt;Configuring this Kerberos to log into CMU&lt;/h3&gt;
&lt;p&gt;Unlike MIT Kerberos, Windows Kerberos isn’t configured using a config file,
but rather with registry keys that can be managed using Group Policy. wow
so enterprisey&lt;/p&gt;
&lt;p&gt;I found &lt;a href=&quot;https://www.garyhawkins.me.uk/non-domain-mit-kerberos-logins-on-windows-10/&quot;&gt;this tutorial&lt;/a&gt;
to be the best resource on how to configure this for my computer, using the
&lt;code&gt;ksetup&lt;/code&gt; command (built-in if you have the Kerberos support installed).&lt;/p&gt;
&lt;h3&gt;Logging into the CMU Kerberos domain&lt;/h3&gt;
&lt;p&gt;Finally, the moment of truth: I had everything set up with &lt;code&gt;ksetup&lt;/code&gt;, and tried
to log into CMU:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;C:&amp;gt; runas /user:hduvall@ANDREW.CMU.EDU cmd&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;1787: The security database on the server does not have a computer account for this workstation&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As it turns out, there’s some extra steps in the tutorial above that are needed
to actually allow non-domain computers to log in like this. Seeing as I don’t
have access to the Kerberos Domain Controller, I had to give up on this route.&lt;/p&gt;
&lt;h2&gt;Modifying Windows OpenSSH to use MIT Kerberos&lt;/h2&gt;
&lt;p&gt;My next step was to get the SSH ported for Windows to use non-built-in Kerberos.
Before you ask, yes I tried PuTTY as well but that didn’t work.&lt;/p&gt;
&lt;h3&gt;Installing MIT Kerberos manually&lt;/h3&gt;
&lt;p&gt;In order to actually use non-built-in Kerberos, I had to have a non-built-in
Kerberos built. I downloaded &lt;a href=&quot;https://web.mit.edu/kerberos/dist/index.html&quot;&gt;MIT Kerberos 1.19.2&lt;/a&gt;
from their release page, and it was really simple to compile and install
according to the instructions in the source.&lt;/p&gt;
&lt;h3&gt;Installing Windows OpenSSH, linking against MIT Kerberos&lt;/h3&gt;
&lt;p&gt;The Windows OpenSSH is &lt;a href=&quot;https://github.com/PowerShell/openssh-portable&quot;&gt;hosted on GitHub&lt;/a&gt;
and has clear instructions for how to install as well… so long as you have
Visual Studio 2015. I have Visual Studio 2019 so I had to modify some PowerShell
scripts by hand to get it to detect my build system correctly.&lt;/p&gt;
&lt;p&gt;I also had to manually roll back to pull request that shimmed in SSPI for
GSSAPI, making it link against the GSSAPI provided by my installation of MIT
Kerberos instead. Editing the code wasn’t too hard, but I had to edit all the
&lt;code&gt;.vcxproj&lt;/code&gt; build files to get it to find headers/link correctly.&lt;/p&gt;
&lt;p&gt;All in all it was a lot of messy, manual work that really only benefits me, so
I didn’t bother making a pull request or even pushing to GitHub.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of SSH using Kerberos to automatically log in to CMU servers&quot; title=&quot;I can log in without a password now!&quot; loading=&quot;lazy&quot; width=&quot;963&quot; height=&quot;313&quot; src=&quot;/_astro/ssh-using-kerberos_Z2qP5Lq.webp&quot; /&gt;&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Windows</category></item><item><title>So It Was Actually Lyme Disease</title><link>https://www.hazelduvall.dev/blog/posts/2021-08-19-so-it-was-actually-lyme-disease.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-08-19-so-it-was-actually-lyme-disease.html</guid><pubDate>Thu, 19 Aug 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So as I mentioned two posts ago, I had a pacemaker put in. Initially, the
doctors thought it was “Athletic Heart Syndrome” but that didn’t really make
any sense since I don’t work out that much. They put in a lab for
&lt;a href=&quot;https://en.wikipedia.org/wiki/Lyme_disease&quot;&gt;Lyme Disease&lt;/a&gt; which came back
positive.&lt;/p&gt;
&lt;p&gt;This makes a lot more sense, since I do regularly go for walks and runs in a
wooded area with known deer. I guess a tick bit me and I never noticed.&lt;/p&gt;
&lt;p&gt;The strangest part is that I didn’t get any of the other usual symptoms of
Lyme, just &lt;a href=&quot;https://www.cdc.gov/lyme/treatment/lymecarditis.html&quot;&gt;Lyme Carditis&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The other symptoms also have a much higher prevalence than Carditis, so the
doctors figured I was very unlucky to have it strike like this but very lucky
to have it be caught in time.&lt;/p&gt;
&lt;p&gt;I’m taking IV antibiotics for the next weeks, right up until August 27th,
switching to oral antibiotics provided my condition improves. I have a
semi-permanent IV in my arm called a PICC line to allow me to take the
antibiotics at home, and after that I’ll be fully cleared to go back to
exercise!&lt;/p&gt;
&lt;p&gt;I can’t wait to finally be better and really hope this works.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Xtreme Hakyll Upgrades</title><link>https://www.hazelduvall.dev/blog/posts/2021-08-16-xtreme-hakyll-upgrades.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-08-16-xtreme-hakyll-upgrades.html</guid><pubDate>Mon, 16 Aug 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is sort of a tradition how: I get more free time, decide to work on my
blog, and instead of actually writing posts I work on the backend and don’t
actually post about it until I’m done, at which point I’ve started to run out
of free time.&lt;/p&gt;
&lt;p&gt;Fortunately, this time I have a lot more free time, and the upgrades are
actually complete! Really! For real this time! (ok not really I still want
to implement syntax highlighting eventually but that’s for later ig)&lt;/p&gt;
&lt;p&gt;The thing I’ve done: taken Hakyll’s incremental compilation abilities and
extendend them to work better with my “numbered post list with links between
them” format.&lt;/p&gt;
&lt;h2&gt;Why Hakyll’s Dependency Tracking is Currently Not Good Enough&lt;/h2&gt;
&lt;p&gt;With standard Hakyll, if all posts link to each other (see each
other’s titles), then updating one post will update all the other posts via
a link like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;post 1 --(depends on)-&amp;gt; post 2 --(depends on)-&amp;gt; ... --(depends on)-&amp;gt; post n&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, I’m only viewing a post’s &lt;em&gt;title&lt;/em&gt;, not anything about its body, so
a post should only be re-compiled when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It’s source file changes&lt;/li&gt;
&lt;li&gt;It depends on a post whose source file has changed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;because source file changes are the only way for metadata to potentially
change. Side note: depending on the metadata directly is a bit harder, with
what I know now it may be possible but what I have works currently and is a
bit better for numbered post lists in general.&lt;/p&gt;
&lt;h2&gt;How I Changed It&lt;/h2&gt;
&lt;p&gt;I added a new &lt;code&gt;PostMetadataDependency&lt;/code&gt; type to the &lt;code&gt;Dependency&lt;/code&gt; enum, as well as a &lt;code&gt;numberedPostListMap&lt;/code&gt; to the &lt;code&gt;DependencyFacts&lt;/code&gt; struct. Every time you make a numbered post list and use fields in its context to view titles/urls of other
pages, it makes a &lt;code&gt;PostMetadataDependency&lt;/code&gt; for that page through the magic of
the &lt;code&gt;Compiler&lt;/code&gt; monad.&lt;/p&gt;
&lt;p&gt;If this sounds similar to how Hakyll already works, that’s because it is.
Here’s the key difference: &lt;strong&gt;You can have a &lt;code&gt;PostMetadataDependency&lt;/code&gt; on
&lt;code&gt;Nothing&lt;/code&gt;&lt;/strong&gt;. Why would you want this? Say you are adding a new post to the end
of the current list of posts. This will be the new last post. The previous last post, which didn’t have a link to any later post, now needs a link to the new
last post as a later post. How else can you model “please re-compile if
something that doesn’t exist yet happens to exist in the future”?&lt;/p&gt;
&lt;p&gt;The implementation is not elegant. I don’t know Haskell very well, and Hakyll
is quite a complicated library with many layers to dig through. In addition to
&lt;code&gt;Dependencies.hs&lt;/code&gt;, I also had to modify &lt;code&gt;Rules.hs&lt;/code&gt; (for a marker of whether
something was a numbered post list), &lt;code&gt;Rules/Internal.hs&lt;/code&gt; (for combining all
those markers into a map of all numbered post lists), and &lt;code&gt;Runtime.hs&lt;/code&gt; (for
getting that map from the result of the &lt;code&gt;Rules&lt;/code&gt; monad and passing that to
&lt;code&gt;Dependencies.hs&lt;/code&gt;). Oh and also &lt;code&gt;Binary&lt;/code&gt; serialization/deserialization for all
the new datastructures I created. All in all it took a lot more effort than I
expected.&lt;/p&gt;
&lt;h2&gt;Was It Worth It?&lt;/h2&gt;
&lt;p&gt;Sort of. It wasn’t a huge deal in the first place anyways, as a rebuild of all
posts is very fast. But gosh darn it, if Hakyll advertises incremental
compilation, then ima use it, even if I have to implement it myself.&lt;/p&gt;
&lt;p&gt;I may also write a more thought-out blog post going into exactly how Hakyll’s
&lt;code&gt;Compiler&lt;/code&gt; and other systems work, now that I’ve read and re-read so much of
that code. Will have to be soon because I’m liable to forget it :P&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; my blog compiles v fast because i made it do that with much
haskell effort&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Hakyll</category></item><item><title>So I Have A Pacemaker Now</title><link>https://www.hazelduvall.dev/blog/posts/2021-08-15-so-i-have-a-pacemaker-now.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-08-15-so-i-have-a-pacemaker-now.html</guid><pubDate>Sun, 15 Aug 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, I was admitted to the hospital because I felt my heart start to beat
wrong, and it turns out I was right: a combination of skipped beats and
lowering heart rate led to low blood pressure and led to me almost fainting
while still lying down (in the hospital bed)! The doctors gave me something to
temporarily raise my heart rate so I didn’t black out on the spot, and within
the hour I was scheduled for surgery.&lt;/p&gt;
&lt;p&gt;Fortunately, the surgery was a huge success and I was discharged the next day
(!!!). I can’t be thankful enough towards the entire cardiac team for making it
go as smoothly as it did. I’m still recovering &amp;amp; the doctor’s orders are to not
exercise for the next few weeks and stay in the area until the follow-up
appointment. While I’m peeved at the change in schedule (not being able to go
back to college as soon), I’m just grateful to still be here, with my family,
even having the possibility of full recovery.&lt;/p&gt;
&lt;p&gt;Another fortunate thing is while this happened during my Facebook internship,
it was the last week and I already had all my tasks done. My manager was very
understanding and let me take as much sick time as I needed. I’m thankful to
everyone on my team there as well, for getting me through the internship and
making it a good experience even with that hiccup at the end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; I’m fine and won’t die, thanks everyone!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Working at Facebook</title><link>https://www.hazelduvall.dev/blog/posts/2021-06-21-working-at-facebook.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-06-21-working-at-facebook.html</guid><description>A young and naïve intern details his experiences of not even 5 weeks at a large tech company</description><pubDate>Mon, 21 Jun 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I think I’ve mentioned this in a previous blog, but ya I have summer internship
at Facebook. A big part of it was probably my school, as there are a lot of
other CMU rising juniors and seniors and graduate students here as well (all at
the same start date for convenience), but I like to think part of it was also a
good interview performance (what can I say i know some graph algorithms).&lt;/p&gt;
&lt;p&gt;They had a whole team selection process, and probably because I put
“comfort using Rust(lang) = high” on the sheet and had systems just below AI in
terms of project preference, I was put on an infrastructure team working on a
large Rust code base.&lt;/p&gt;
&lt;h3&gt;The Code&lt;/h3&gt;
&lt;p&gt;Ima wax poetic about how cool Rust is for a sec because this is my blog and I
make the rules here. So: &lt;strong&gt;&lt;em&gt;Rust is super cool holy cow.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rustfmt&lt;/code&gt; makes sure no matter who writes the code, it all becomes readable
at the end because everything from capitalization to spacing is opinionated.&lt;/li&gt;
&lt;li&gt;Builder patterns are encouraged by the language and safe to use and work
pretty darn well as a result. If you don’t know what a builder pattern is,
it’s basically something like&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; foo &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; FooBuilder&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            .&lt;/span&gt;&lt;span&gt;set_bar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            .&lt;/span&gt;&lt;span&gt;set_kaz&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;17&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            .&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;The type system makes everything safe and even though you “fight” the
compiler at times it’s really all about making you code better and I love
the very descriptive and colorful error messages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Seriously if you have a project you’re considering doing in C or C++ due to
performance reasons just use Rust you’ll thank me later.&lt;/p&gt;
&lt;p&gt;Ok so back to Facebook: because the team is using Rust, and they didn’t quite
expect an intern to have known Rust before the internship when they were
drafting up the project plan, I breezed through the first few tasks and am now
working on pretty real stuff that hopefully will be useful to other engineers
there. Can’t divulge too much about the project specifics unfortunately but
it’s fairly widely used internal app, I’m just adding more user-facing metrics
to it.&lt;/p&gt;
&lt;p&gt;At this point, I’m sort of in a Rust + SQL part of the project, and may even
transfer over to Python + SQL once I need to use another certain internal
framework. I haven’t actually used too much SQL before, but &lt;a href=&quot;https://docs.rs/sql-builder/3.1.1/sql_builder/struct.SqlBuilder.html&quot;&gt;SQL Builder&lt;/a&gt;
has been very nice to use in Rust, and the &lt;a href=&quot;https://prestodb.io/docs/current/&quot;&gt;Presto Docs&lt;/a&gt;
are surprisingly well-writen and informative. Sub-queries, &lt;code&gt;GROUP BY&lt;/code&gt;, and
&lt;code&gt;FILTER(WHERE ...)&lt;/code&gt; are magic, query executors doin some crazy stuff to get
those to be efficient with so much data.&lt;/p&gt;
&lt;p&gt;Internal documentation alternates between “We have something from 2016 on it
but it’s horribly out of date, just read the code (oh wait you don’t even know
what the thing you’re looking for is called? sux to be u)” and “Everything is
explained perfectly and has examples and test cases and is formatted well”
which is hm so I’m glad I have a good manager. Which brings me to…&lt;/p&gt;
&lt;h3&gt;The People&lt;/h3&gt;
&lt;p&gt;With few execptions, everyone I’ve met at Facebook has been very nice and
willing to help. My team and especially my manager + peers have been extremely
helpful at answering my n00b questions at any hour of the workday and making me
feel welcome and appreciated. Another great thing, what I also liked about CMU
and TJHSST and what I should expect from most good tech companies, is that
everyone is super smart. I like being surrounded by smart and hard-working
people because that in energizing and I like both the environment and how it
makes me a better person.&lt;/p&gt;
&lt;p&gt;In some respects, I may have been lucky, because hearing from a few other
interns (during optional organized “just get on a call and hang out with
other interns in an unmonitored breakout room” that of course I’m going to go
to) it seems not all the teams are this quality or they’re having trouble
adapting to work and not getting enough support or they don’t really like the
work they were assigned or whatever. I can get jazzed about lots of
computer-related stuff and like to be sociable so that helps, but I’m still
very glad I got the team I did.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;TL;DR Facebook is a neat place with neat projects&lt;/strong&gt;, still don’t know how
much I agree with their ethics even with them trying to turn themselves around.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>disasm on AWS Lambda!</title><link>https://www.hazelduvall.dev/blog/posts/2021-05-23-disasm-aws-lambda.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-05-23-disasm-aws-lambda.html</guid><pubDate>Sun, 23 May 2021 12:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;2023 Update: This Site Is No Longer Online&lt;/h2&gt;
&lt;p&gt;rest of post preseved for posterity :)&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I’d like to formally announce that my fork of &lt;a href=&quot;https://github.com/ret2jazzy/disasm.pro/&quot;&gt;ret2jazzy’s&lt;/a&gt;
&lt;a href=&quot;https://disasm.pro/&quot;&gt;disasm.pro&lt;/a&gt; is back up and being hosted on AWS Lambda!&lt;/p&gt;
&lt;p&gt;This was a quick project to re-familiarize myself with cloud computing paradigms
and technologies before my internship starts (tomorrow, I guess). Thanks to
needing a custom fork of the keystone disassembler, this whole project took a
bit longer than expected.&lt;/p&gt;
&lt;p&gt;The solution I ended up going with was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Putting the entire project in a Docker container
&lt;ul&gt;
&lt;li&gt;This overcame my previous distaste for Docker quite well, because it worked
very well and solved the messy dependency problem nicely.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Using &lt;a href=&quot;https://pypi.org/project/serverless-wsgi/&quot;&gt;serverless-wsgi&lt;/a&gt; to glue
the AWS Lambda interface to the existing WSGI outline.
&lt;ul&gt;
&lt;li&gt;Using the raw Serverless Framework did not work very well at all,
disappointingly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Putting the Lambda function behind AWS API Gateway at its two POST endpoints,
&lt;code&gt;/assemble&lt;/code&gt; and &lt;code&gt;/disassemble&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Using CloudFront to redirect any requests not to those endpoints towards an
S3 bucket containing all the static files.
&lt;ul&gt;
&lt;li&gt;The container and API gateway actually also contain support for static files
on their own, but this makes things faster for sure.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So all in all, my goals for this project were accomplished: I stood up my tool
again and also learned a lot about AWS. Hopefully I won’t have to do this again
for a while, debugging everything was awful!&lt;/p&gt;</content:encoded><category>AWS</category><category>Web</category></item><item><title>The Housing Search Is Brutal But At Least It&apos;s Almost Over</title><link>https://www.hazelduvall.dev/blog/posts/2021-05-19-housing-search-is-brutal-but-at-least-its-over.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-05-19-housing-search-is-brutal-but-at-least-its-over.html</guid><pubDate>Wed, 19 May 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For the past couple of days, I have been searching for off-campus housing.&lt;/p&gt;
&lt;p&gt;As for why, I have been spoiled by my current apartment and years of living in
my own bedroom, enough to never want to repeat the experience of my Freshman
year when I lived with an annoying roommate in a tiny flat. This led to my 4
main criteria: 1 bedroom (not a studio), close to campus, nice kitchen,
hardwood floors.&lt;/p&gt;
&lt;p&gt;Yes, I’m that picky. Spoilers: no I did not find something matching all of those
again like I lived in this semester.&lt;/p&gt;
&lt;h2&gt;The Cause&lt;/h2&gt;
&lt;p&gt;When signing up for university housing, I didn’t get a single-bed room. They
were flat out (wow I wonder why) and some other early riser decided to
register themselves as my roommate without so much as contacting me first. I
don’t blame them though; I blame the university for such a high-pressure system.
You technically have all semester to find roommate pairs, but everyone I knew
either had a roommate group already planned or was living on their own, and the
one new potential roommate I found flaked on me in the last week before room
selection. So, some other poor chap, also without a roommate and with only 5
minutes to register his room before his timeslot is over, sees a room with an
empty spot on a low floor and just goes ahead because our sleep schedules
aren’t that far off.&lt;/p&gt;
&lt;p&gt;Now, I could deal with their sleep schedule. Maybe. I’m also picky about that.
But what prompted the whole off-campus housing search was what I could glean
about their personality from their online profile. Basically, they’re the kind
of person to start a non-profit for their College application and ditch it after
they graduate High School. I &lt;strong&gt;&lt;em&gt;despise&lt;/em&gt;&lt;/strong&gt; that whole concept, having gotten roped
in to one of those once, and I don’t note it anywhere because I don’t believe
it accomplished anything of value. Heck, I even list my &lt;a href=&quot;https://github.com/hazelduvall/1kbwc&quot;&gt;1kbwc game engine&lt;/a&gt;
project and not that because at least the silly Python-and-pure-JS app shows
&lt;em&gt;something&lt;/em&gt; about my capabilities.&lt;/p&gt;
&lt;p&gt;Is that a bit too judgemental of someone else? Probably yes. I’m sure it
could’ve worked out, especially if I tried hard to rid myself of this animus.
But after what happened Freshman year I don’t want to take chances. So anyways,
back to the housing search:&lt;/p&gt;
&lt;h2&gt;The Result&lt;/h2&gt;
&lt;p&gt;Before this process, I had no idea how to conduct a housing search. This was
always the realm of my parents when I was but a wee lad (duh), and I was content
with University housing until the above. So I was not prepared for the process
of “scheduling a tour only for ‘oh sorry someone else bought it already’” to
happen like 5 times in a row. Talking to my parents, apparently this is normal
for hot housing areas. People want property so you gotta play the game to get
it. The landlords control the supply and everyone else is fighting over the
demand.&lt;/p&gt;
&lt;p&gt;Another thing I was not prepared for was “sorry we don’t sell to
undergrads.” This came up more often than you’d expect, because I seemingly do
not look or sound like an undergraduate to most people, so when I say I go to
CMU they peg me as a graduate at first glance. I’m not entirely sure why some
places have a ban on undergradutes, some hypotheses are that they make too much
noise late at night or don’t do a good enough job with cleaning/maintenance.
Neither of those apply to me I don’t think but some were pretty hard-line about
this, which sucked because that landlord controlled a lot of property.&lt;/p&gt;
&lt;h2&gt;The Conclusion&lt;/h2&gt;
&lt;p&gt;In the end, I found a place that matched 3 of my 4 criteria, only difference
being that it’s carpeted (I can live with that, so long as that’s not in the
kitchen). I was pleasantly surprised when I inquired about it two days in a row
and the unit was still available, so I sent in the application and fee and am
now hoping for the best. The rent is slightly more expensive than CMU rent, but
the latter was for &lt;em&gt;half of a bedroom&lt;/em&gt; while this is for a full bedroom so I
think that’s fair. Fortunately the rent will be completely covered by what I’ll
make over the summer, so lucky to have no issues there.&lt;/p&gt;
&lt;p&gt;In any case, I’m glad it’s all over, I can feel the difference in not having
the weight of “where will I live next semster” on my shoulders. Everything
tends to work out :)&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>S21 Semester Actually Over!</title><link>https://www.hazelduvall.dev/blog/posts/2021-05-17-s21-actually-over.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-05-17-s21-actually-over.html</guid><pubDate>Mon, 17 May 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Can’t believe the day has finally come!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All my finals and final projects are turned in&lt;/li&gt;
&lt;li&gt;I’m moved out of my apartment and am back in my parents’ house with my family.&lt;/li&gt;
&lt;li&gt;Just chilling before starting my remote internship on the 24th&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s very nice to not have any more deadlines, although it’s sort of been like
that ever since last Monday (with the exception of my 15-210 final on that day
and my Japanese final paper due Friday), so I’m already in that Summer groove.
I will definitely hang out with friends more, or at least try to, now that we
are all relatively free of deadline shackles. Here’s to a good Summer ‘21!&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>Spring &apos;21 Semester Almost Over??</title><link>https://www.hazelduvall.dev/blog/posts/2021-04-28-s20-almost-over.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-04-28-s20-almost-over.html</guid><pubDate>Wed, 28 Apr 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow that was fast! I can’t believe that in just another week, all my classes
will have finished their lecture series and, with the exception of one class,
all my final projects will be turned in and done with. After that, I’ll have
an entire week to just relax before I pack up and move home for my remote
internship.&lt;/p&gt;
&lt;p&gt;It’s a little early to do a semester post-mortem, but there are some things I
would like to comment on now before my probable series that comes out truly
after-the-fact:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Despite a less crazy school and work schedule, I still didn’t feel like I had
enough time to do all the projects I wanted. With the exception of Februrary,
I did very little art or personal programming projects. I’m not sure if this
was not having time (what it felt like) or just not making time.&lt;/li&gt;
&lt;li&gt;I did well in all my classes. Perfect GPA maintained
(&lt;i&gt;sunglasses emoji&lt;/i&gt;).&lt;/li&gt;
&lt;li&gt;Could’ve done better, but I maintained a good workout schedule.&lt;/li&gt;
&lt;li&gt;Could’ve done much better, but I was able to see friends often, especially
with Frisbee practice becoming a regular thing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oh yeah and it was my birthday the other day too (: Family came, and it was
nice to see them again for a little bit, and I’ll see them again soon.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>Grad School Thoughts and a Blog Post That Resonated With Me</title><link>https://www.hazelduvall.dev/blog/posts/2021-04-10-grad-school-thoughts-resonance.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-04-10-grad-school-thoughts-resonance.html</guid><pubDate>Sat, 10 Apr 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The scene: someone in the &lt;a href=&quot;https://discord.gg/2NNhbFU&quot;&gt;CMU Discord&lt;/a&gt;, #scs
channel, posted a link to a &lt;a href=&quot;https://www.alexirpan.com/2017/04/19/acss.html&quot;&gt;fairly cool article about a misuse of algorithmic
complexity in social sciences&lt;/a&gt;.
The writing was engaging, and I had time to kill, so I started reading &lt;a href=&quot;https://www.alexirpan.com/2016/07/17/ml-sleep.html&quot;&gt;other
linked posts&lt;/a&gt;, and
eventually got around to reading their latest post, &lt;a href=&quot;https://www.alexirpan.com/2021/04/07/grad-school-5years.html&quot;&gt;“The 5 Year Update on
Skipping Grad School (and Whether I’d Recommend It)”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you know me, or have seen my &lt;a href=&quot;2019-06-02-senior-research.html&quot;&gt;early&lt;/a&gt;
&lt;a href=&quot;2019-04-08-opencv-chessboard-test.html&quot;&gt;posts&lt;/a&gt; (or really even the existence
of the &lt;a href=&quot;/blog/tags/ai.html&quot;&gt;AI&lt;/a&gt; and &lt;a href=&quot;/blog/tags/computer-vision.html&quot;&gt;CV&lt;/a&gt; tags), you’ll
know &lt;em&gt;really&lt;/em&gt; like AI and CV and potentially even be comfortable starting to do
research in those areas. In fact that’s part of what I did for my internship at
Aerospace, and if things go flawlessly, at Facebook as well. And yet, I don’t
find myself looking forward to doing a PhD or Grad School or really even doing
undergraduate research.&lt;/p&gt;
&lt;p&gt;I think that’s part of why Alex Irpan’s post and especially its &lt;a href=&quot;https://www.alexirpan.com/2016/01/03/grad-school.html&quot;&gt;prequel from
when he was an undergrad&lt;/a&gt;
struck me. Here’s an eloquent guy, who’s done some pretty cool Reinforcement
Learning research with robots at Google for crying out loud, talking about a
similar feeling he was having as an undergrad. He put into words some of the
reasons why, even though I think research is super cool to get done and is very
nice to read, it can just get too overwhelming. Their writing is much more
engaging than I can replicate here, but if you too are at least considering
Grad School then I think both articles (and the ones he links to) are worth a
read.&lt;/p&gt;
&lt;p&gt;After reading these, my current plan of “just try to go into industry with a
little undergrad research experience from a summer maybe and hope you can do
cool industry research as well” hasn’t changed, and if anything seems even more
feasible. Even if I don’t end up doing research, AI-adjacent SWE would be fun
as well, just a different set of problems to overcome.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;“Wow a Saturday post??? ur wildin” ya u better know it I just wanted to share
this article lol&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>My Mile Time</title><link>https://www.hazelduvall.dev/blog/posts/2021-04-05-mile-time.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-04-05-mile-time.html</guid><pubDate>Mon, 05 Apr 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I ran my first sub-6 mile today, a 5:59! I had no idea I could do this!&lt;/p&gt;
&lt;p&gt;A bit of background: the captains of the Mr. Yuk Ultimate Frisbee team (which I
am a part of, and is still running practices despite all games being cancelled)
posted a challenge in the group Slack. If anyone could beat their 5:50 mile
time, the speedster would get a special prize. While I wasn’t expecting to beat
their time, let alone come anywhere close, I thought it might be fun to try
because I haven’t run a timed mile since Sophomore year of high school, when I
ran a 6:43.&lt;/p&gt;
&lt;p&gt;One reason I may have improved: Since last summer, I have been running every
week. At first it was just simple Frisbee track practice drills to keep my
stamina from last year, then it was training with my brother and his actual
track coach to improve speed and sprinting form, and now for the entire spring
semester I have been working on distance runs, slowly pushing from 4 to 5 to
now almost 6 miles as my last run.&lt;/p&gt;
&lt;p&gt;And this is all on top of other weight training I do. I am probably at my
current peak fitness, even counting Junior year of high school when I was doing
wrestling practice 6 days a week or Freshman Spring of college when I could
(just barely) play 6 frisbee games in 2 days.&lt;/p&gt;
&lt;p&gt;This feels good. So good, in fact, that I remembered my blog and also that I
forgot to post last weekend. Oh well, I didn’t have much to write about
anyways except for more cool CV projects.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;bunny rendered with a &amp;quot;hot&amp;quot; color palette&quot; title=&quot;hot bunni&quot; loading=&quot;lazy&quot; width=&quot;523&quot; height=&quot;541&quot; src=&quot;/_astro/hot-bunny_ZqhkeM.webp&quot; /&gt;&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Happy Pi Day!</title><link>https://www.hazelduvall.dev/blog/posts/2021-03-14-happy-pi-day.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-03-14-happy-pi-day.html</guid><pubDate>Sun, 14 Mar 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At 4:32PM today, it was 3/14 15:92, which is approximately &lt;span&gt;&lt;span&gt;π\pi&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;π&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Very neat.&lt;/p&gt;
&lt;p&gt;Don’t have too much to talk about so have a grab-bag of things which I think
are pretty cool:&lt;/p&gt;
&lt;h2&gt;My Friend’s Blog&lt;/h2&gt;
&lt;p&gt;Just getting started, but has a really good first post! &lt;a href=&quot;https://williamoconnell.me/blog/post/magic-pirate/&quot;&gt;https://williamoconnell.me/blog/post/magic-pirate/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Someone Else’s Blog&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://jez.io/thoughts/on-leaving-facebook/&quot;&gt;jez.io&lt;/a&gt; has some cool posts too.
I forget how exactly I came across this blog, but it’s pretty good too.&lt;/p&gt;
&lt;h2&gt;A CV Project I’ve Done&lt;/h2&gt;
&lt;p&gt;This was for class, doing some (non real-time) AR composition:&lt;/p&gt;
&lt;div&gt;
&lt;figure&gt;&lt;/figure&gt;
The Kung-Fu Panda trailer is composited onto a textbook cover
&lt;/div&gt;
Yes it is very shaky, no I&apos;m not entirely sure why (probably because the
homography computation was unstable, wasn&apos;t sure how to fix before the
deadline).</content:encoded><category>daily thoughts</category><category>Computer Vision</category></item><item><title>The Closest Thing We Have to Magic Nowadays</title><link>https://www.hazelduvall.dev/blog/posts/2021-02-28-the-closest-thing-we-have-to-magic-nowadays.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-02-28-the-closest-thing-we-have-to-magic-nowadays.html</guid><pubDate>Sun, 28 Feb 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Alright, so this is a bit silly, but it’s one of those things I think about
often enough that I’m writing about here lol.&lt;/p&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;I’m fascinated by magic systems that seem to have some sort of underlying
ruleset to them. I’ve been heavily influenced by magitech-like series such as
&lt;a href=&quot;https://en.wikipedia.org/wiki/A_Certain_Scientific_Railgun&quot;&gt;A Certain Scientific
Railgun&lt;/a&gt;,
&lt;a href=&quot;https://en.wikipedia.org/wiki/Ender%27s_Game&quot;&gt;Ender’s Game&lt;/a&gt;, and &lt;a href=&quot;http://www.scpwiki.com/&quot;&gt;The SCP wiki
&lt;/a&gt; (especially works by &lt;a href=&quot;http://www.scpwiki.com/djkaktus&quot;&gt;&lt;code&gt;djkaktus&lt;/code&gt;
&lt;/a&gt;), as well as more fantasy-esque works like
&lt;a href=&quot;https://quietandantagonism.com/&quot;&gt;Quiet &amp;amp; Antagonism&lt;/a&gt; (this one is very obscure but &lt;strong&gt;I
love it so much&lt;/strong&gt; it’s definitely worth a read) and &lt;a href=&quot;https://en.wikipedia.org/wiki/Bone_%28comics%29&quot;&gt;Bone
&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;OK so maybe not all of these are all quite rule-based as I would like for a
good example, but the point is that when I think of “magic,” I don’t
immediately default to thinking about western wizard-style magic like
&lt;a href=&quot;https://dnd.wizards.com/&quot;&gt;DnD&lt;/a&gt;,
&lt;a href=&quot;https://en.wikipedia.org/wiki/The_Lord_of_the_Rings&quot;&gt;LotR&lt;/a&gt;,
&lt;a href=&quot;https://en.wikipedia.org/wiki/Harry_Potter&quot;&gt;Harry Potter&lt;/a&gt;, or magic from
&lt;a href=&quot;https://en.wikipedia.org/wiki/KonoSuba&quot;&gt;insert&lt;/a&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/That_Time_I_Got_Reincarnated_as_a_Slime&quot;&gt;generic&lt;/a&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Is_It_Wrong_to_Try_to_Pick_Up_Girls_in_a_Dungeon%3F&quot;&gt;isekai&lt;/a&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Re:Zero_%E2%88%92_Starting_Life_in_Another_World&quot;&gt;fantasy&lt;/a&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Overlord_%28novel_series%29&quot;&gt;here&lt;/a&gt;, or maybe a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Hunter_%C3%97_Hunter&quot;&gt;shonen&lt;/a&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Naruto&quot;&gt;fantasy&lt;/a&gt;’s magic system.&lt;/p&gt;
&lt;p&gt;Narratively, a rule system sets up some extra hurdles the protagonists must
work around, showing their perseverance, or some neat things they can exploit
in unexpected ways, showing their cleverness. A good rule system allows for
endless possibilities, even outside of what’s shown in the story. I like this
because it gets me thinking, “how would &lt;em&gt;I&lt;/em&gt; go about figuring that out?” which
is very engaging.&lt;/p&gt;
&lt;h2&gt;What this has to do with real life&lt;/h2&gt;
&lt;p&gt;There are plenty of &lt;a href=&quot;https://cdn.discordapp.com/attachments/388924578812002336/815641900374556752/EvQkCeDXUAcvfuJ.png&quot;&gt;memes&lt;/a&gt;
about it, but just think: electronics &lt;em&gt;are&lt;/em&gt; basically magic. I’m taking an
electronics class right now (&lt;a href=&quot;https://courses.ece.cmu.edu/18310&quot;&gt;18-310, Fundamentals of Semiconductor Devices&lt;/a&gt;),
and a lot of the stuff we are learning just blows my mind how scientists were
able to figure out in the first place. And yet, here we are: we have a model
for exactly how little invisible &quot;&quot;&quot;electrons&quot;&quot;&quot; move around inside materials
carrying some intrinsic, quantized &quot;&quot;&quot;charge&quot;&quot;&quot; and if you set things up just
right we can, to borrow from the overly simple phrasing in the meme, “make sand
think.” But this isn’t magic, it’s real! For everything we learn in this
course, we can set up an experiment to test it! People already have!&lt;/p&gt;
&lt;p&gt;To me, that’s the most awesome part; this world &lt;em&gt;does&lt;/em&gt; have a “magic system”
and I’m learning it right now. Sure it isn’t, “if I think hard enough, I can
shoot a fireball out of my fingers,” but that’d be too easy and those are the
lazy systems I hate anyways. You need to know a lot of math and physics and
chemistry to do anything here, but that’s OK. All I can say is that I’m
thankful to be around when so much has been figured out already, and we have
the tools to figure so much more out too.&lt;/p&gt;
&lt;h2&gt;Aside&lt;/h2&gt;
&lt;p&gt;I would like to see more math used in magic systems. Math is so important in
real science, after all. This has motivated me to start designing my own
world/magic system, the both of which are still woefully incomplete. I hope to
one day write a story using it, but who knows if that day will ever come lol.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Cooking at College!</title><link>https://www.hazelduvall.dev/blog/posts/2021-02-21-cooking.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-02-21-cooking.html</guid><pubDate>Sun, 21 Feb 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As a college student with ample amounts of free time, I have taken up cooking
as a semi-hobby to pass the time and remind me of home. I say “semi-hobby”
because I don’t have a full passion for it, but I do still like to cook and
practice it regularly&lt;/p&gt;
&lt;h2&gt;Some things I’ve cooked:&lt;/h2&gt;
&lt;p&gt;In chronological order:&lt;/p&gt;
&lt;figure&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;1000&quot; src=&quot;/_astro/2021-tetrazzini_D349j.webp&quot; /&gt;&lt;/p&gt;
&lt;figcaption&gt;&lt;em&gt;Chicken Tetrazzini&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;1000&quot; src=&quot;/_astro/2021-spaghetti_ZCmaoV.webp&quot; /&gt;&lt;/p&gt;
&lt;figcaption&gt;&lt;em&gt;Spaghetti with Meat Sauce&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;1000&quot; src=&quot;/_astro/2021-soup_Z2kyGry.webp&quot; /&gt;&lt;/p&gt;
&lt;figcaption&gt;&lt;em&gt;Cream of Chicken Vegetable Noodle Soup&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;1000&quot; src=&quot;/_astro/2021-taco-stuff_1rdwhe.webp&quot; /&gt;&lt;/p&gt;
&lt;figcaption&gt;&lt;em&gt;Taco Materials (Tacos not shown)&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;
&lt;p&gt;&lt;img loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;1000&quot; src=&quot;/_astro/2021-lasagne_Z13XFmr.webp&quot; /&gt;&lt;/p&gt;
&lt;figcaption&gt;&lt;em&gt;Lasagne&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;In order of best to worst (at least to my taste buds):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Lasagne&lt;/li&gt;
&lt;li&gt;Chicken Tetrazzini&lt;/li&gt;
&lt;li&gt;Cream of Chicken Vegetable Noodle Soup&lt;/li&gt;
&lt;li&gt;Spaghetti with Meat Sauce&lt;/li&gt;
&lt;li&gt;Taco Materials&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;This rating is mainly because it didn’t store in the fridge well; when it
was fresh I would’ve rated it higher than the soup.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do not that this isn’t an extensive list, as I have cooked other stuff but
didn’t take pictures. Cheesy Scrambled Eggs, Turkey Sandwiches, and of course
the classic Peanut Butter and Banana Bagel have been staples of my diet as well.&lt;/p&gt;
&lt;h2&gt;History of these dishes&lt;/h2&gt;
&lt;p&gt;Everything except the soup is from a recipe my Dad has taught me. Of course
he’s not the sole inventor of any of them but I do believe each of these
recipes has been tweaked significantly by him, over the course of many years
cooking for our family, to be the dishes I know and love. I’m currently in the
process of copying his cookbook one recipe at a time by phoning home to ask
and then making them here. I like the food I grew up with, and unless I decide
to start cooking more Korean-style stuff due to the Korean grocery nearby, I
think it will stay that way for a bit longer.&lt;/p&gt;
&lt;h2&gt;Future plans&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cheese Gnocchi Soup
&lt;ul&gt;
&lt;li&gt;From a “Dead-simple cookbook” my grandparents got me, where each recipe
assumes you have access to full kitchen supplies and many different spices
and wines and meats and no, I do not have those. I didn’t skimp while
buying stuff for my apartment kitchen, but I didn’t go all-out either. I do
not have a mixing machine or a pressure cooker or wine or 5 different
spices geez.&lt;/li&gt;
&lt;li&gt;So, this recipe will be modified but I think the base will still taste
pretty good.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Chocolate Chip Cookies
&lt;ul&gt;
&lt;li&gt;This is where my Dad’s experimentation truly paid off. You think you’ve had
the best chocolate chip cookies? You have not had these cookies yet. I know
it’s cliche but really you have to try them. If you’re on campus, shoot me
a message and I’ll bring you some once I’ve made them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>The Senate Trial</title><link>https://www.hazelduvall.dev/blog/posts/2021-02-13-the-senate-trial.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-02-13-the-senate-trial.html</guid><pubDate>Sat, 13 Feb 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So, &lt;a href=&quot;https://www.msn.com/en-us/news/other/trump-acquitted-in-impeachment-trial-7-gop-senators-vote-with-democrats-to-convict/ar-BB1dEO0c&quot;&gt;it happened&lt;/a&gt;.
After being impeached for &lt;a href=&quot;https://www.cnn.com/2021/01/11/politics/house-articles-of-impeachment/index.html&quot;&gt;incitement of insurrection&lt;/a&gt;,
Donald Trump was acquitted by the Senate by a vote of 57-43, 7 Republicans
joining the 50 Democrats in a total 10 shy of the 2/3 super-majority needed to
convict.&lt;/p&gt;
&lt;p&gt;What follows is a summary of everything I personally have heard about the case:&lt;/p&gt;
&lt;h2&gt;Main Arguments For Convicting&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;There is little ambiguity that Trump &lt;a href=&quot;https://www.usnews.com/news/politics/articles/2021-01-13/transcript-of-trumps-speech-at-rally-before-us-capitol-riot&quot;&gt;directed his crowd towards the Capitol Jan. 6 with violence-imbued language&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;Near the end of his speech: “And if you don’t fight like hell, you’re not
going to have a country anymore. … So let’s walk down Pennsylvania
Avenue.”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;He did not immediately call the crowd off once it was clear they were
turning violent and breaking into the building.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nytimes.com/2021/01/06/us/politics/twitter-deletes-trump-tweet.html&quot;&gt;Later statements&lt;/a&gt;
did not help either and could be interpreted as praising the rioters.&lt;/li&gt;
&lt;li&gt;Trump’s language and messaging from the November election until the riot
consistently repeated the falsehood that we won the election and that the
entire system was rigged against him in a massive conspiracy. These claims
are false, but believing in them can be dangerous especially when you think
the very fate of your country is on the line.
&lt;ul&gt;
&lt;li&gt;Trump must’ve been aware of this, and besides, ignorance of a massive
angry mob does not excuse you for continuously inciting a massive angry
mob.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;All of this could be interpreted as Trump wanting a coup attempt to overturn
the election that he knew he lost. It should be unforgivable for anyone, let
alone a sitting president, to do this.&lt;/li&gt;
&lt;li&gt;Conviction would prevent Trump from holding office again, a good thing given
what happened last time he was removed from office.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Main Arguments Against Convicting&lt;/h2&gt;
&lt;p&gt;I’ll order these from most to least convincing, at least for me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Conviction/impeachment is primarily a tool to remove a president from office,
an argument that &lt;a href=&quot;https://www.msn.com/en-us/news/politics/mcconnell-tells-gop-hell-vote-to-acquit-impeachment-update/ar-BB1dEtbO&quot;&gt;Mitch McConnell used despite also denouncing Trump’s actions for many of the reasons above&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;Counterargument: conviction/impeachment can also be a tool to keep a former
president from holding office again, which is pertinent in this case. If it
was only for removal, then a lame-duck president could do absolutely
anything they wanted their last few days in office because it’d be unlikely
the House and Senate could move fast enough to impeach and convict.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Trump was simply exercising his first amendment rights! Democrats say
“fight” all the time in their speeches too!
&lt;ul&gt;
&lt;li&gt;Counterargument: First amendment rights are not absolute; see any number
of hate-speech crimes (where similarly, plausible threats of violence
occur) or perhaps leaking confidential information. Both are &quot;&quot;&quot;just people
saying things :)&quot;&quot;&quot; but clearly illegal. There is not much different about
this from the former, and in fact the statements are higher (implicit
threats against the highest legislative body in the nation, not just a
single person).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The riot wasn’t actually that bad.
&lt;ul&gt;
&lt;li&gt;Counterargument: they literally broke into the Capitol. That alone makes
the United States look like an utter fool on the world stage. The fact that
a sitting president was seen to incite it makes it even worse.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Antifa did it
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://projects.propublica.org/parler-capitol-videos/?id=YcQOeXTOuGhu&quot;&gt;No, i think it was the far right actually&lt;/a&gt;. &lt;a href=&quot;https://www.nytimes.com/interactive/2021/02/04/us/capitol-arrests.html&quot;&gt;Too many of the people convicted have ties to far right groups for that to hold water&lt;/a&gt; (use &lt;a href=&quot;https://github.com/iamadamdev/bypass-paywalls-chrome&quot;&gt;https://github.com/iamadamdev/bypass-paywalls-chrome&lt;/a&gt; btw, great extension).&lt;/li&gt;
&lt;li&gt;Honestly if you actually believe this I don’t think I can convince you.
Just know that buying into a conspiracy that requires you to constantly
doubt every piece of information you come across isn’t always a good one.
Occam’s Razor please.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;I think from reading this you know what side of the fence I sit on. I believe
that convicting Donald Trump would’ve been the correct thing to do and I highly
respect the 7 Republican senators as well as the entire body of Democratic ones
who voted to convict. Trump’s stain on America’s reputation will not be
forgotten any time soon, especially by the world at large. I worry for what this
means for America’s future.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Politics</category></item><item><title>First Week at College! Or, How to Install MPL (MaPLe)</title><link>https://www.hazelduvall.dev/blog/posts/2021-02-07-first-week.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-02-07-first-week.html</guid><pubDate>Sun, 07 Feb 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;All in all, not too bad of a week at all! Classes haven’t ramped up yet, so all
the assignments this week were easy introductory ones. Computer Vision (16-385)
should shape up to be a very good class based on the lectures and the fact that
programming homework is 70% of the grade (I love programming!!).&lt;/p&gt;
&lt;p&gt;For being alone in an apartment during quarantine, I’ve been doing pretty well.
I’ve taken lots of walks around campus and Schenley Park as well as participate
in Figuary (figure drawing month).&lt;/p&gt;
&lt;p&gt;However, one day I got really bored with all my free time, and decided to do
something programming-related instead. My Parallel Computing (15-210) class uses
&lt;a href=&quot;https://github.com/mpllang/mpl&quot;&gt;MaPLe&lt;/a&gt;, a home-grown fork of the
&lt;a href=&quot;http://mlton.org/&quot;&gt;MLton&lt;/a&gt; implementation of
&lt;a href=&quot;https://en.wikipedia.org/wiki/Standard_ML&quot;&gt;Standard ML&lt;/a&gt; (SML) designed with
simple parallel/concurrent programming primitives. We learned SML syntax and
functional programming concepts in &lt;a href=&quot;https://www.cs.cmu.edu/~15150/&quot;&gt;15-150&lt;/a&gt;,
and I already have some experience in parallel from TJ, so using it shouldn’t be
too hard.&lt;/p&gt;
&lt;p&gt;CMU provides the MPL compiler on their remote servers, available by SSH, but I
prefer to work locally. So, like ya do, I compiled MPL myself using their
instructions. It was surprisingly easy so I thought I’d share how to do it with
the rest of my class. Here is the full guide I wrote up and shared on the class
&lt;a href=&quot;https://diderot.one/&quot;&gt;Diderot&lt;/a&gt;:&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Learn you a local MPL install for great good!&lt;/h1&gt;
&lt;p&gt;Hello everyone! Today I will be showing you how to install MPL (MaPLe, the
Parallel SML compiler thingy) locally, on your own machine, because you might
be like me and not prefer to do things on the Andrew machines.&lt;/p&gt;
&lt;p&gt;First, like with any good recipe, I will tell you my life story. A long time
ago, I did not know how to compile things. Then, I started using CentOS (for
various reasons) which never has up-to-date packages. Wanting to use up-to-date
packages, I had to learn how to compile things. Along the way, I got pretty
good at compiling things, even if they were hard to set up.&lt;/p&gt;
&lt;p&gt;Fortunately for you, MPL falls on the easier side of programs you have to
compile yourself! And without further ado, let’s get right into that:&lt;/p&gt;
&lt;h2&gt;Installing Dependencies&lt;/h2&gt;
&lt;p&gt;I will be providing two sets of instructions: one for those running Debian 10
(or derivatives like Ubuntu or Linux Mint), and those running MacOS Big Sur. I
have tested both sets on respective fresh and squeaky clean installations, so
if they don’t work for you then too bad good luck fixing your environment. If
you are running another Linux Distribution (or even worse, a BSD *shudders*),
then I trust you known what you are doing well enough to adapt these
instructions to your own liking. If you are on Windows, just get Debian for
WSL (so much better than using a virtual machine)&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3&gt;Installing Packaged Dependencies&lt;/h3&gt;
&lt;p&gt;According to its README.md, MPL requires the following packages to be
installed for it to be built (N.B. make sure your package manager is working
and up-to-date before running these!).&lt;/p&gt;
&lt;p&gt;Debian:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;span&gt; apt&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; build-essential&lt;/span&gt;&lt;span&gt; libgmp-dev&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; wget&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;macOS: First, install XCode from the app store and homebrew from
&lt;a href=&quot;https://brew.sh/&quot;&gt;https://brew.sh/&lt;/a&gt; if you haven’t already. Then, run&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;xcode-select&lt;/span&gt;&lt;span&gt; --install&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;brew&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; coreutils&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; gcc&lt;/span&gt;&lt;span&gt; gmp&lt;/span&gt;&lt;span&gt; mlton&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Note: binutils, make, and bash should be present by default on macOS with the
XCode CLI tools installed. If they are not and compiling MPL fails, run
&lt;code&gt;brew install binutils make bash&lt;/code&gt; and try to compile MPL again)&lt;/p&gt;
&lt;h3&gt;Installing MLton (Linux only)&lt;/h3&gt;
&lt;p&gt;Homebrew is nice enough to have a pre-compiled MLton in their package
repository, but unfortunately Debian is not so nice. So, we will simply have
to download the package and install it ourselves&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;wget&lt;/span&gt;&lt;span&gt; https://github.com/MLton/mlton/releases/download/on-20201002-release/mlton-20201002-1.amd64-linux.tgz&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;tar&lt;/span&gt;&lt;span&gt; xzf&lt;/span&gt;&lt;span&gt; mlton-20201002-1.amd64-linux.tgz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, skip ahead to the “Installing MPL” section and complete the first step,
replacing all instances of mpl with mlton. Then, change directory back to
where you ran the wget command and run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; mlton-20201002-1.amd64-linux&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;make&lt;/span&gt;&lt;span&gt; PREFIX=&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span&gt;/.local/mlton&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should have mlton in your path now; try running &lt;code&gt;mlton&lt;/code&gt; with no arguments to
test. If it prints out a version number, you should be set. If not, then idk
try to figure it out.&lt;/p&gt;
&lt;h2&gt;Compiling MPL&lt;/h2&gt;
&lt;p&gt;For both systems: change directory to a suitable build folder, and run the
following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; https://github.com/MPLlang/mpl.git&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; mpl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, on Linux:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;make&lt;/span&gt;&lt;span&gt; all&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MacOS is a bit tougher, but not too much. MPL was written with Linux in mind,
and as such, uses a few Linux-isms in its code. So, I made a
&lt;a href=&quot;https://gist.github.com/hazelduvall/0ed62747ee765ed663eeca59a141c820&quot;&gt;patch&lt;/a&gt; that
gets rid of those in a way that doesn’t affect the functionality of MPL too
much (I don’t think, at least). The following commands download and apply that
patch, as well as tell the Makefile to use XCode tools:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; -sSL&lt;/span&gt;&lt;span&gt; https://gist.githubusercontent.com/hazelduvall/0ed62747ee765ed663eeca59a141c820/raw/d65448c91fac52e59afd58982cad0663488842ac/0001-MacOS-fixes.patch&lt;/span&gt;&lt;span&gt; -o&lt;/span&gt;&lt;span&gt; 0001-MacOS-fixes.patch&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; apply&lt;/span&gt;&lt;span&gt; 0001-MacOS-fixes.patch&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;make&lt;/span&gt;&lt;span&gt; AR=ar&lt;/span&gt;&lt;span&gt; RANLIB=ranlib&lt;/span&gt;&lt;span&gt; all&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Installing MPL&lt;/h2&gt;
&lt;p&gt;Now, if you’re like me, you like to just type &lt;code&gt;mpl&lt;/code&gt; to run something instead of
&lt;code&gt;/huge/path/to/a/build/folder/mpl/build/bin/mpl&lt;/code&gt;. I like to put built binaries
in a &lt;code&gt;~/.local&lt;/code&gt; directory, and then add that directory to my path. Doing that
for mpl:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; $HOME&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; .local/mpl&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# Run this line in your shell, and also add it to your ~/.bashrc or ~/.zshrc or similar:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; PATH&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$PATH:$HOME/.local/mpl/bin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, navigate to the directory you cloned mpl to earlier, and run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;make&lt;/span&gt;&lt;span&gt; PREFIX=&lt;/span&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;span&gt;/.local/mpl&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it! You’re done, congratulations! As a test, go to the examples
folder of mpl and try to run make nqueens to see if the compiler works
correctly.&lt;/p&gt;
&lt;h1&gt;DISCLAIMER: DESPITE MY BEST EFFORTS IN TRYING ALL THESE STEPS MYSELF, THEY ARE NOT GUARANTEED TO WORK FOR YOU.&lt;/h1&gt;
&lt;p&gt;So please, use your head and a search engine before typing a comment about how
you got a scary error message and want someone to fix it.&lt;/p&gt;
&lt;h1&gt;ALSO READ THE WHOLE THING PLEASE&lt;/h1&gt;
&lt;hr /&gt;
&lt;section&gt;&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;As much as I would also like to provide instructions for native Windows, being a Windows power-user myself, the preferred method for emulating a Unix environment, MSYS2/MinGW64 &lt;a href=&quot;http://mlton.org/RunningOnMinGW&quot;&gt;doesn’t let MLton use fork() for some reason&lt;/a&gt;, and I staunchly refuse to recommend Cygwin, so yeah just use WSL. &lt;a href=&quot;#user-content-fnref-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The astute reader might have noticed that we are not using the latest version of MLton. That is because the Github release for it with glibc 2.23 is broken (bad ld.so in the mlton-compile executable, “only” requires a minor change to the released bin/mlton script that is more trouble than it’s worth to put here), and the other version is for glibc 2.31 which is too new for Debian. &lt;a href=&quot;#user-content-fnref-2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>Last Post of Winter Break!</title><link>https://www.hazelduvall.dev/blog/posts/2021-01-31-last-post-of-winter-break.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-01-31-last-post-of-winter-break.html</guid><pubDate>Sun, 31 Jan 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow I can’t believe winter break is over! And yet at the same time, I can’t
believe it was so long.&lt;/p&gt;
&lt;p&gt;I’ve moved into my new university apartment faily close to campus and am writing
this post from my trusty laptop in the now-designated computer room. Due to the
de-densifying policy CMU has adopted, because this was a 3 person apartment that
2 people inhabited last semester, I am the only one in it this time around.&lt;/p&gt;
&lt;p&gt;It’s pretty nice, having the space for 3 people all to myself. I don’t feel
cramped at all (unlike the last place, smaller than just this room and I had a
roommate!).&lt;/p&gt;
&lt;p&gt;COVID is still putting a damper on meeting people, though. There’s a mandatory
14-day “quarantine” where all classes will be online and extra-dorm activities
will be limited to exercise and grocery runs so long as you stay on the CMU
campus. Not even seeing anyone in-person outside of people on your floor, and
even then it has to be outdoors + with masks!&lt;/p&gt;
&lt;p&gt;All told though, I’m very lucky given the circumstances. No sickness, good setup
(thanks Mom and Dad for helping me move in; you guys were awesome and I couldn’t
have done it without you) and 100% prepared for classes.&lt;/p&gt;
&lt;p&gt;See y’all in a couple weeks, by which time I may or may not be overwhelmed with
classes! We’ll see.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>My First &quot;Real&quot; Open Source Contribution</title><link>https://www.hazelduvall.dev/blog/posts/2021-01-24-open-source-contribution.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-01-24-open-source-contribution.html</guid><pubDate>Sun, 24 Jan 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Near &lt;a href=&quot;./2020-12-21-finally-more-time.html&quot;&gt;the beginning of winter break&lt;/a&gt;, I
had an idea to contribute an implementation to ONNX, Microsoft’s Open Source
neural network accelerator. I had just been dropped from the Aerospace
internship (due to accepting a position for Facebook’s summer software
engineering internship (more on that later I swear)), and AI ideas were still
fresh in my mind, so it was a good opportunity to keep my programming skills
sharp.&lt;/p&gt;
&lt;p&gt;I’m proud to announce that I’ve done it! You can check out my work &lt;a href=&quot;https://github.com/onnx/models/blob/master/vision/object_detection_segmentation/fcn/README.md&quot;&gt;here&lt;/a&gt;.
The full README.md is a bit too wordy to include (and honestly is redundant to
list again here), but I’ll include the description section so you have an idea
of what I was working on.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Description&lt;/h3&gt;
&lt;p&gt;Fully Convolutional Networks (FCNs) are a neural network model for real-time
class-wise image segmentation. As the name implies, every weight layer in the
network is convolutional. The final layer has the same height/width as the input
image, making FCNs a useful tool for doing dense pixel-wise predictions without
a significant amount of postprocessing. Being fully convolutional also provides
great flexibility in the resolutions this model can handle.&lt;/p&gt;
&lt;p&gt;The specific model I contributed can detect 20 different classes, corresponding
to the &lt;a href=&quot;https://cocodataset.org/#home&quot;&gt;COCO 2012&lt;/a&gt; class analouges of the
&lt;a href=&quot;http://host.robots.ox.ac.uk/pascal/VOC/&quot;&gt;PASCAL VOC&lt;/a&gt; classes. The models were
sourced from PyTorch models pre-trained on the COCO train2017 dataset using this
class subset.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Oh, also, something I should mention: today is a double post! Go check out
&lt;a href=&quot;./2021-01-23-facestuff-1.html&quot;&gt;the previous post&lt;/a&gt; for more code stuff I did recently.&lt;/p&gt;</content:encoded><category>AI</category><category>Computer Vision</category><category>projects</category></item><item><title>Live2D Demo Application Expanded</title><link>https://www.hazelduvall.dev/blog/posts/2021-01-23-facestuff-1.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-01-23-facestuff-1.html</guid><pubDate>Sat, 23 Jan 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The slow burn project I mentioned
&lt;a href=&quot;./2021-01-08-live2d-license-close-reading.html&quot;&gt;earlier&lt;/a&gt; has concluded for now
at least. Not for lack of progress, but actually because I completed a major
milestone in actually getting it to work!&lt;/p&gt;
&lt;h3&gt;What does it do?&lt;/h3&gt;
&lt;p&gt;Currently, &lt;a href=&quot;https://github.com/hazelduvall/facestuff&quot;&gt;the application&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Renders a sample Live2D model at 60fps&lt;/li&gt;
&lt;li&gt;Takes an image from the webcam and detects a face in it at 4fps&lt;/li&gt;
&lt;li&gt;Composites the two images together&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This required the intersection of many different graphics technologies which I’m
not sure were all made to go together:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL&lt;/a&gt; creates the window and initializes an &lt;a href=&quot;https://www.opengl.org/&quot;&gt;OpenGL&lt;/a&gt; context (together with &lt;a href=&quot;https://www.opengl.org/sdk/libs/GLEW/&quot;&gt;GLEW&lt;/a&gt; to help with the dynamic loading that OpenGL requires)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Live2D/CubismNativeFramework&quot;&gt;Live2D Cubism Native Framework&lt;/a&gt; loads the proprietary model format and renders it (when in the OpenGL context).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://opencv.org/&quot;&gt;OpenCV&lt;/a&gt; handles opening the webcam and detecting a face in it&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hazelduvall/ACGL&quot;&gt;A Custom GUI Library&lt;/a&gt; built on top of SDL spawns the two threads to do Live2D rendering and OpenCV maths at the same time, as well as controlling the layout of the scene.&lt;/li&gt;
&lt;li&gt;And finally, raw OpenGL shaders that I had to &lt;a href=&quot;http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/&quot;&gt;find a good tutorial for&lt;/a&gt; to render the OpenCV data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the end, I got a pretty good result:&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://www.hazelduvall.dev/static/live2D_OpenCV_SDL.png&quot; alt=&quot;A console showing debug info on the left, and an SDL frame showing a Live2D model on the right. The background of the frame is the screen this is displayed on, causing it to recurse for a few iterations.&quot; title=&quot;Pretty trippy, huh?&quot; /&gt;
  &lt;figcaption&gt;&lt;em&gt;I pointed the webcam at the screen to make this&lt;/em&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’ve put the project on hold for now, partly because I’ve accomplished
a lot of what I wanted to do (get all these libraries working with one another
at all), but mostly because School is coming up soon! I leave the 29th and start
February 1st which is very close. Also I went skiing in the meantime which was
very fun and put a damper in doing many things code-related during it. Anyways,
see you next time!&lt;/p&gt;</content:encoded><category>Computer Vision</category><category>projects</category></item><item><title>Old Thoughts About Learning</title><link>https://www.hazelduvall.dev/blog/posts/2021-01-13-old-thoughts.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-01-13-old-thoughts.html</guid><pubDate>Wed, 13 Jan 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, I had the idea to look through some old AP Literature writing I did.
Not to brag too much but uh, it’s pretty good?? I’m including an essay that
I’m really proud of here:&lt;/p&gt;
&lt;h2&gt;Creative Writing: Nonfiction (Reworked)&lt;/h2&gt;
&lt;p&gt;30 May 2019&lt;/p&gt;
&lt;p&gt;As I transition from high school to college, I’ve done some thinking about how
I best learn. After all, so I’m told, college is where students are challenged
to pace themselves, the bulk of the work being done outside the classroom. This
in and of itself doesn’t bother me; I can time-manage and slog through mountains
of homework with the best of ‘em. No, what bothered me is this: if I don’t know
my own strengths, then I can’t play to them to save time or shore up my own
weaknesses.&lt;/p&gt;
&lt;p&gt;After some experimentation, I could conclusively point out things that are not
my strengths. I’m impatient; I’m set in my ways; I can’t focus on future plans;
I have limited people skills; I underestimate the value of others; I can’t think
fast, or strategically; I can’t visualize shapes clearly; I don’t have an ear
for music. I was told I think too poorly of myself, that I can improve on any of
these things with time, that professionals have dedicated years of their life
towards learning something I can’t possibly hope to understand in one week. I
had a hard time swallowing this. It seemed like shifting the blame, which is
pretty shifty if you ask me.&lt;/p&gt;
&lt;p&gt;As an example, the other day, I tried to play the piano. &lt;em&gt;It’s just notes on a
page, those are easy to read,&lt;/em&gt; I thought. Individually, yes, after a good ten
seconds of counting up or down from middle C. Then came the unanticipated
challenge of getting my fingers to press the right notes without looking. Then
came stringing all that together at a reasonable pace. I pressed through for a
bit longer, learning to play a few bars, but then I got discouraged by lack of
immediate progress. It was just another frustrating riff on other unfamiliar
subjects I’d tried before, like art, Tetris, and basketball.&lt;/p&gt;
&lt;p&gt;So, what was I comfortable with, able to do quickly and without a second
thought? Programming comes to mind. What’s so special that makes me suited for
it? Broad information synthesis? A keen eye for details? A knack for language
of any sort? Raw experience curated by years of specialization? If it’s the last
of the bunch, I feel cheated. I want to get good at a lot of things, and yet the
only path towards that goal is time? What a ripoff. Time is precious. It doesn’t
seem physically possible, let alone desirable, to spend every waking hour
working towards one goal after another.&lt;/p&gt;
&lt;p&gt;As I thought these things, I confided in a friend. He told me this: your
perspective is totally off. First, you need to stop comparing yourself to
others; it’s unhealthy. Then, you need to slap yourself in the face, tell
yourself you &lt;em&gt;are&lt;/em&gt; good enough, and stick to whatever constructive practice
regimen is necessary. You will get better. You might not ever reach your goal,
but you will get better, which is what matters. I was shook, for lack of a
better word. Logically speaking, it makes sense that good artists, musicians,
public speakers, and sports players spend years perfecting their craft, years
which I don’t have under my belt. And yet some notion possessed me to think I
could get the same results, only better and more quickly, simply because I could
understand &lt;em&gt;what&lt;/em&gt; they were doing, not ever really &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Being relieved of that thought train was sobering. It did nothing to lessen the
frustration I felt when I couldn’t draw a precise curved line, couldn’t beat my
friend at Tetris, or couldn’t put that darn large orange ball in the darn red
hoop. Instead of submitting, though, I now know what to do: keep going. I’m
still at a loss for how to play to my strengths. But by some miracle of hard
work I made it through high school, and gosh darn it, I’ll work my butt off to
keep improving through college and life as well. In my opinion, that’s what
being human is all about.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;In the almost 2 years since I wrote this, I’ve kept the same perspective. And
wouldn’t you know it, &lt;em&gt;I’ve gotten a lot better at things&lt;/em&gt;. My art is leagues
above where is was before (and I still have leagues to go). I didn’t practice
Tetris or basketball, but I did practice some &lt;a href=&quot;./2020-08-22-skullgirls.html&quot;&gt;fighting
games&lt;/a&gt;,
and now I can beat everyone I know (not always easily, and none specialize in
fighting games either and I still get destroyed online). I’ve also been working
out (weight training + some running) and have seen steady improvement there
too.&lt;/p&gt;
&lt;p&gt;Having this mindset and being able to see the results has been very gratifying.
It’s such a privilege to know that yes, if I put in the work, I really can do
anything. I’m also fortunate to be in an environment where it’s even possible
to put in so much work. Thanks to the support of my family and friends, I have
achieved all my goals in school and mini-goals in hobbies. I look forward to
doing even more!&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Writing</category></item><item><title>Live2D License Close Reading</title><link>https://www.hazelduvall.dev/blog/posts/2021-01-08-live2d-license-close-reading.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2021-01-08-live2d-license-close-reading.html</guid><pubDate>Fri, 08 Jan 2021 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One project that’s been on slow burn throughout this winter break has been an
attempt to get a &lt;a href=&quot;https://www.live2d.com/en/&quot;&gt;Live2D Cubism&lt;/a&gt; avatar animated
using &lt;a href=&quot;https://opencv.org/&quot;&gt;OpenCV&lt;/a&gt; facial detection routines.&lt;/p&gt;
&lt;p&gt;Becuase Live2D provides pretty much zero useful documentation in English, I have
resorted to “copying” their &lt;a href=&quot;https://github.com/Live2D/CubismNativeSamples/tree/develop/Samples/OpenGL/Demo/proj.win.cmake&quot;&gt;Windows OpenGL Demo&lt;/a&gt;
to try to make something useful. By “copying,” I mean that I had their code up
on one screen, while I took note of the structure and names and typed similarly
structured and named code on another screen. Like the good citizen I am, I had
the thought, “wait, could it be possible that this isn’t legal?”&lt;/p&gt;
&lt;h2&gt;Turns out it’s legal&lt;/h2&gt;
&lt;p&gt;…although not for the reasons you may think. Follow along with the &lt;a href=&quot;https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html&quot;&gt;Live2D Open Software License Agreement&lt;/a&gt;
if you woul like. Keep in mind that I Am Not A Lawyer so anything I say should
be taken with a grain of salt.&lt;/p&gt;
&lt;h3&gt;Restrictive things&lt;/h3&gt;
&lt;p&gt;Most of the license seems to be dedicated to preserving the license itself. Many
clauses are about how, under no circumstance, can anyone come into possession of
licensed code or use it without first agreeing to the license (also no
re-licensing under a different license because duh). Once that’s done, the
restrictions are fairly minimal: just don’t commit crimes, and also if you
publish your source code that uses this open source code, Live2D can use your
code too. Live2D also retains half the copyright to any modifications you make
to their source code. Also you need to keep all copyright notices intact.&lt;/p&gt;
&lt;h3&gt;Things you can do&lt;/h3&gt;
&lt;p&gt;You can redistribute the code (if people agree to the license), you can publish
code that is based off the license, you can make modifications (to the code, not
the licensing). You also retain full ownership over the parts of Derivative
Works that aren’t Live2D code. All in all, it seems to be a fairly permissive
license.&lt;/p&gt;
&lt;h3&gt;Where does my copying fall under this?&lt;/h3&gt;
&lt;p&gt;I was worried that my copying might be not allowed at first glance according to
section 5.1, titled &lt;strong&gt;No Modifications&lt;/strong&gt;. It basically says the same thing as
the title. Under certain interpretations, my “copying” might be construed as a
modification (because the same result could’ve been achieved by first copying,
then modifying, or really the modifications were happening on a copy in my
brain, idk). The Software protected by this license includes all copies and
modified copies, so the code would still be protected by the license. If it had
included language like “Only Live2D is allowed to distributed the Software” then
I would’ve been out of luck. Fortunately, that is not the case and I am still
allowed to distribute this regardless of whether or not courts would think what
I have done counts as a copy.&lt;/p&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;p&gt;Still very unfinished at the moment, but &lt;a href=&quot;https://github.com/hazelduvall/facestuff&quot;&gt;here it is&lt;/a&gt;. Pay no mind to &lt;a href=&quot;https://github.com/hazelduvall/facestuff-rust&quot;&gt;a previous version written in Rust&lt;/a&gt;;
it current has no Live2D components, just an OpenCV demo with a broken Windows
API hook (that I plan on fixing later, then porting the Live2D logic to, can’t
be a copy/modification if it’s in an entirely different language).&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Also sorry for not posting recently; Winter Break has been very fun and relaxing
but putting stuff on my blog has not been part of my routine. I think leaving
it like this, with monthly-ish posts might be good enough. No pressure on
myself, though. Maybe I’ll post about an AI thing again one day (after my PR
gets accepted probably, be excited ;)).&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Computer Vision</category></item><item><title>Finally, More Time</title><link>https://www.hazelduvall.dev/blog/posts/2020-12-21-finally-more-time.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-12-21-finally-more-time.html</guid><pubDate>Mon, 21 Dec 2020 12:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;What am I going to do with myself?&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;Finally, the Winter semester has ended, and I finally have time to do non-school
activities!&lt;/p&gt;
&lt;p&gt;I have a couple things planned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work on contributing the FCN model for &lt;a href=&quot;https://github.com/onnx/models&quot;&gt;https://github.com/onnx/models&lt;/a&gt;.
Currently, I am installing ONNX and ONNXRuntime which has proved a bit harder
than &lt;code&gt;pip install onnx onnxruntime&lt;/code&gt; for various reasons, unfortunately.&lt;/li&gt;
&lt;li&gt;Do some art! Daily practice is the plan. I found some warmup routines to do,
which includes a lot more gesture drawings than I was comfortable with but I
think it has already made me a bit better
&lt;ul&gt;
&lt;li&gt;Part of this will be to make some personal art, and part will also be to
make some art for AAC’s Secret Santa art exchange.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Walk my dogs&lt;/li&gt;
&lt;li&gt;Practice Skullgirls?&lt;/li&gt;
&lt;li&gt;Other AI reading/programming stuff as it comes up&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Wait I don’t see any Aerospace on that list…&lt;/h3&gt;
&lt;p&gt;Yeah, and not just because I forgot to mention it. As a consequence for
accepting another internship for the upcoming summer, I am no longer allowed to
work for Aerospace during the school year. This kinda sucks, because I was
having a great time there getting to do cool AI research. I hope the next
internship (which I will elaborate on more in a later post) will be as good.&lt;/p&gt;
&lt;p&gt;I mostly accepted the other offer because I wanted to explore more. The
obscene amounts of money had little to do with it (although that is a nice
perk). I am under a confidentiality agreement on the exact amount, but it
definitely exceeded by expectation for intern pay, even for a California-based
company.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Other notable updates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Might get my first B in college due to getting consistent B’s on 21-355 exams.
Although maybe not? Depends on whether the exams are out of 115 or 100 points.&lt;/li&gt;
&lt;li&gt;I have been compiling &lt;code&gt;pandoc&lt;/code&gt; on the machine hosting this blog for almost 2
full days now. It is still not done and probably won’t be for another 2 days
at this rate. Fun!&lt;/li&gt;
&lt;li&gt;Friends have organized a modded Minecraft server known as &lt;a href=&quot;https://gitlab.com/1F335/modpackman/-/tree/JEFFREY-3&quot;&gt;JEFFREY&lt;/a&gt;,
which is pretty fun even though I am not very good at Minecraft.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>daily thoughts</category></item><item><title>Free time =&gt; More Hakyll Upgrades</title><link>https://www.hazelduvall.dev/blog/posts/2020-11-25-more-hakyll-upgrades.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-11-25-more-hakyll-upgrades.html</guid><pubDate>Wed, 25 Nov 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Thanksgiving break, woo! I finally had enough time on my hands to get around to
something that had been bothering me with this blog for a while: Hakyll doesn’t
do dependency tracking right.&lt;/p&gt;
&lt;h3&gt;Wait, What?&lt;/h3&gt;
&lt;p&gt;Yes you heard me right. Haskell is a very complicated language, and Hakyll takes
full advantage of all those complications to make a surprisingly robust system.
But the robustness makes it a bit inflexible, which is why I ended up having to
write a lot of extra code to get these numeric page ids.&lt;/p&gt;
&lt;p&gt;But that’s not what was broken.&lt;/p&gt;
&lt;h2&gt;The thing wrong with Hakyll&lt;/h2&gt;
&lt;p&gt;Hakyll’s main branch treats the metadata of a page changing and the actual page content changing as
the same event. This is troublesome because my pages all depend on the ones
directly before and after it for metadata like title and date. This is separate
from the actual content of the page before or after, so if the metadata stays
the same, I do not expect the pages to rebuild.&lt;/p&gt;
&lt;p&gt;“Not so fast,” says Hakyll. “This page you just edited is out of date, so I must
propogate that out-of-dateness to its neighbors because I cannot tell if just
the body changed or the metadata did as well.” Ok, that’s all fair and good, but
this new out-of-dateness ends up propogating to those page’s neighbors, then
their neighbors, so if any page gets updated, all pages get rebuilt.&lt;/p&gt;
&lt;h3&gt;I would rather this didn’t happen&lt;/h3&gt;
&lt;p&gt;So after understanding all that, I forked the Hakyll engine and added that
distinction with an extra &lt;code&gt;MetadataDependency&lt;/code&gt; type in addition to the existing
&lt;code&gt;IdentifierDependency&lt;/code&gt; and &lt;code&gt;PatternDependency&lt;/code&gt; ones that already existed. I then
tweaked the dependency resolver to skip over metadata dependencies when doing
the dependency update chain things, and only look 1 neighbor level deep when
doing the out-of-date marking for metadata dependencies.&lt;/p&gt;
&lt;h2&gt;Did that work?&lt;/h2&gt;
&lt;p&gt;After many long hours, yes! It did! But there’s a new slight problem: adding a
page (like this blog post) to the end of the list does not update the old most
recent page to have a “next page” link that points to it. This is because the
old page did not have a metadata dependency on the non-existent page.&lt;/p&gt;
&lt;p&gt;It’s possible to fix this by checking if there are any new metadata
dependencies in the check for out-of-date items, but I am exhausted from
writing so much Haskell already so I think I’ll leave that for another day.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Anyways, Happy Turkey Day tomorrow!&lt;/p&gt;</content:encoded><category>Hakyll</category><category>daily thoughts</category></item><item><title>Online Identity</title><link>https://www.hazelduvall.dev/blog/posts/2020-11-20-online-identity.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-11-20-online-identity.html</guid><pubDate>Fri, 20 Nov 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;[insert joke about japanese “three faces” or native american “two wolves” idk]&lt;/p&gt;
&lt;h3&gt;So do I have two faces?&lt;/h3&gt;
&lt;p&gt;I would say yes, actually. “Hazel Duvall” is one of them, and ”█████████” is the
other.&lt;/p&gt;
&lt;h3&gt;Wait like multiple identity disorder??&lt;/h3&gt;
&lt;p&gt;No, just my online presence :P&lt;/p&gt;
&lt;p&gt;It’s been like this for a while now, me having multiple separate online “faces”.
There’s a professional one (including this blog, however unprofessional it may
seem), and one much less tied to my real-life presence. However, if you know the
other one, you will probably still be able to find this one. Maybe. I haven’t
tried too hard to doxx myself really, but apparently some people at my school
have been able to put 2-and-2 together when they knew both.&lt;/p&gt;
&lt;h3&gt;Are you going to tell what the other “name” is?&lt;/h3&gt;
&lt;p&gt;I have redacted the name because I am still not comfortable tying the two
together. It’s not that I am ashamed of either; rather, I’m proud of who I am in
both regards. To me, there’s something fun about not having people know who else
I am. It allows me to feel in full control of my identity, which is liberating.
There are things I can do and say without fear of how it would impact how people
see the other me, the physical one who needs to get hired and network and boring
stuff like that.&lt;/p&gt;
&lt;h3&gt;It sounds like you are very attached to this other identity&lt;/h3&gt;
&lt;p&gt;Yup. In fact, I have purposely avoided using the term “true self” or “real self”
because I’m not sure which one that is. Sometimes I’ll feel like Hazel, and other
times I’ll feel like █████████, and all the time I’m still myself. The
identities are similar enough that usually it doesn’t matter. I have the same
core values, just different expressions of interest, different speech patterns,
and different responsibilities. Both can be my true self at different moments
and that’s ok.&lt;/p&gt;
&lt;h2&gt;Sounds like you’re a Furry&lt;/h2&gt;
&lt;p&gt;I don’t know where you got that impression :3&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>But I&apos;m Still Here</title><link>https://www.hazelduvall.dev/blog/posts/2020-10-26-but-im-still-here.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-10-26-but-im-still-here.html</guid><pubDate>Mon, 26 Oct 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi. It’s been a while.&lt;/p&gt;
&lt;p&gt;This week has started off less busy than usual, but it’s still almost to the
point of unmanageability. Not yet though. I’m still trucking.&lt;/p&gt;
&lt;p&gt;Artober has been a bust. I ended up completing 10 drawings, and severely lack
motivation to finish more. It wasn’t the prompts, I liked the prompts, it was
the falling behind and eventually dropping out of the habit.&lt;/p&gt;
&lt;p&gt;Math and Computer Science homework has been going very well, feeling good
making very clever solutions to these problems. But I sort of want to do other
stuff besides just Math and Computer Science homework, ya know?&lt;/p&gt;
&lt;h2&gt;What Would Be Really Fun (right now at least)&lt;/h2&gt;
&lt;p&gt;When I’m bored but don’t really have time to kill, I’ve been browsing &lt;a href=&quot;https://wiki.gbl.gg/w/Main_Page&quot;&gt;The
Mizuumi Wiki&lt;/a&gt;, a wiki for niche/indie fighting
games. I found it by looking up resources for Skullgirls (last mentioned
&lt;a href=&quot;./2020-08-22-skullgirls.html&quot;&gt;here&lt;/a&gt;), but I clicked on the sidebar for other
games and found a lot of fun, weird, and interesting things.&lt;/p&gt;
&lt;p&gt;So basically, I think it might be fun to contribute to that a bit. You know,
just find a fighting game that hasn’t been touched a lot, figure out its
secrets, meditatively record footage of different moves, simple stuff. Not that
I have time for it right now.&lt;/p&gt;
&lt;h3&gt;Other Games&lt;/h3&gt;
&lt;p&gt;My friend also shared some other cool fighting games with me: &lt;a href=&quot;https://plusw.itch.io/vernal-edge-kickstarter-demo&quot;&gt;Vernal
Edge&lt;/a&gt; and &lt;a href=&quot;https://drazglb.itch.io/declines-drops&quot;&gt;Decline’s
Drops&lt;/a&gt;. Both have Smash Bros.-like
combat while actually being a standard 2D platformer, which I think is a really
interesting concept and could actually work. Both of these demos are free, and
I definitely plan on trying these out when I have the time (which I do not
currently).&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Anyways, that’s all for now. I wish I could talk about what I’m doing on
homework more but that’s a little of an academic integrity violation to post
solutions and stuff (which is kind of the only reason why I would talk about
it). Maybe I can talk about the CTF club I’m in next time?&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>I&apos;m Tired</title><link>https://www.hazelduvall.dev/blog/posts/2020-10-16-im-tired.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-10-16-im-tired.html</guid><pubDate>Fri, 16 Oct 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Title says it. I’m beat. Exhausted. Feelin’ it.&lt;/p&gt;
&lt;p&gt;I know exactly why I feel like this: I am overworked. My week is
roughly 65 (!!) hours, which leaves no time to take a break ever. My classes
are already tough, and then I have tutoring and Aerospace on top of that.&lt;/p&gt;
&lt;p&gt;Nothing is hard by itself, it’s just a lot. All of it. The problem is I really
would enjoy doing any of it. I love all the topics I’m taking this semester,
I like tutoring, Aerospace is fun to do AI research, it’s all really good stuff.
And yet, I literally do not have time to do it all.&lt;/p&gt;
&lt;h3&gt;Mistakes were made&lt;/h3&gt;
&lt;p&gt;The bigest mistake was made back last spring, when I signed up for all this
stuff.&lt;/p&gt;
&lt;p&gt;I was just barely keeping my head above water for a few weeks now, and I
finally had a major slip on Wednesday when I forgot to turn in a written
assignement for &lt;a href=&quot;https://www.cs.cmu.edu/~213/&quot;&gt;15-213&lt;/a&gt;. Fortunately, I will be
able to drop the two lowest homeworks (both of which were created by this
mistake), but I really dread this happening again. It totally could, if not in
this class, then some other class.&lt;/p&gt;
&lt;p&gt;I’m asking myself to do the improbable here, trying to stay on top of all these
responsibilities at once, but I still beat myself up over things like this.
Thursday, when I was still blisfully unaware of the slip-up, I had a little bit
of time to do art and relax, for like 1 hour, and I was happy. For once in a
very long week I actually felt good about myself. Then came this morning when
I realized my mistake.&lt;/p&gt;
&lt;h3&gt;The stress is getting to me&lt;/h3&gt;
&lt;p&gt;What right do I have to complain about stress? I have a loving family, good
grades, steady access to food, friends that would listen to me if I told them
about this, paying jobs that would easily hire me full-time if they could, so
why am I so down?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;And yet I know this is the typical thought process of someone who is
depressed, but I refuse to call myself that because “other people must have
it worse and I’m just a big baby.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;I can’t let this affect my work&lt;/h3&gt;
&lt;p&gt;I’m scared of falling behind again. I care too much about all of the things
I’m doing to let any go. I’m trying to catch what little time I have and it
just runs through my fingers.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Tonight I am going to go to bed early. I don’t want to think about this
anymore. Writing this post didn’t help and made me only more frustrated and
potentially even more exhausted from stress later. I can only do so much and
I’ve done enough for now.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Artober Challenges</title><link>https://www.hazelduvall.dev/blog/posts/2020-10-10-artober-challenges.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-10-10-artober-challenges.html</guid><pubDate>Sat, 10 Oct 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TL;DR - So among other things, I am participating in a very strange Artober challenge titled “Cringetober” and I have not posted for a while mainly due to an overwhelming amount of homework and other responsibilities.&lt;/p&gt;
&lt;h3&gt;Origin of Artober&lt;/h3&gt;
&lt;p&gt;Before talking about the art I’m doing, a little history is due. As far as I understand it, in the years before 2020, there was an art challenge known as Inktober that started off small but quickly rose in popularity. The basic premise was that, every day, there was a new prompt for doing a simple inked piece of art. You could make your piece really simple, or really complex, and tag your piece with #inktober and everyone would love it.&lt;/p&gt;
&lt;p&gt;Later, however, the guy behind the original challenge started using his copyright to take down artbooks that people had compiled (of their own art!) that used “Inktober” in the title. This caused backlash in the art community, being seen as unfair, so this year people started to boycott Inktober and instead do an assortment of other daily art challenges for the month of October, collectively referred to as Artober.&lt;/p&gt;
&lt;h3&gt;The Challenge I am doing&lt;/h3&gt;
&lt;p&gt;There are a multitude of Artober challenges, and the one I picked was titled “Cringetober.” The prompts are all things that reference strange internet culture, and I liked it because a) I like strange things and b) the expectations to produce good art based off it is not very high.&lt;/p&gt;
&lt;p&gt;Combining this with my friends’ suggestion of doing daily 1KBWC cards, I have
produced quite the set of cursed images. (I think I last mentioned 1KBWC
&lt;a href=&quot;./2019-06-18-scanning-cards.html&quot;&gt;here&lt;/a&gt;? not sure though, I should do a full
write-up if I haven’t already). Again, I don’t think they count as high-quality
art, but I like them for what they are (very strange) and I like doing them.
It’s a nice break to just not care about responsibilities for a little bit and
make in-jokes for my friends to enjoy.&lt;/p&gt;
&lt;h1&gt;Geez dude you haven’t posted for a while&lt;/h1&gt;
&lt;p&gt;Ya ik. I keep meaning to but keep getting distracted. I only remembered to do something now because I have a free hour, exhausted other entertainment options, and really did not feel like doing more homework. Free hours are rare but it’s good to get thoughts down every once in a while. I’ll maybe update this post with the official Cringetober prompt list if I can. Until next time then!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>So I&apos;m a Tutor Now, Apparently</title><link>https://www.hazelduvall.dev/blog/posts/2020-09-19-so-im-a-tutor-now.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-09-19-so-im-a-tutor-now.html</guid><pubDate>Sat, 19 Sep 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So much for “daily” thoughts amirite?&lt;/p&gt;
&lt;p&gt;As one can infer from the title, I have started a tutoring job in addition to continuing my summer internship part-time as well as attending remote classes. So yes I have been kinda way too busy to type these blog posts until this weekend, when homework has died down a little.&lt;/p&gt;
&lt;h3&gt;Who even hired me as a tutor anyways?&lt;/h3&gt;
&lt;p&gt;CMU’s &lt;strong&gt;Student Academic Success Center&lt;/strong&gt; did, after I applied for it and took a half-semester long training course last spring. Even after the bit of training I feel very inexperienced and have been doing a lot of learning on-the-job.&lt;/p&gt;
&lt;h3&gt;How many tutees are ya tutling?&lt;/h3&gt;
&lt;p&gt;I have no idea if those are actual words. Six, split equally across Saturday and Tuesday. This slots into my schedule fairly nicely.&lt;/p&gt;
&lt;h3&gt;What do you tutle?&lt;/h3&gt;
&lt;p&gt;I will use this word even if it doesn’t exist so help me. A class know inside CMU as 15-151, “Concepts,” or “Prof. Mackey enlightens you while downing a 2-liter bottle of Diet Coke.” I would call it “Introduction to proofs and computer science theory maths” but that’s not as formal as the real course title (which I do not remember because it is so boring and besides, the other titles are much better anyways). 15-151 is a proof-heavy class which is really challenging if you’ve never done math proofs before. I was in that boat my Freshman year, but I quickly learned how to paddle and ended up with a pretty good understanding of the material (I think). The students coming to me also have problems in a similar vein, ranging from not knowing strategies on how to write proofs, not knowing enough definitions, not easily grasping how to apply the definitons, and overall low confidence in their own ability after having been beat down by the first homework.&lt;/p&gt;
&lt;p&gt;This is not to disparage any of them. Anyone coming into CMU is already leagues above the average in terms of problem-solving and general mathematical ability. All of them really do know how to solve these problems, given enough time. Writing and thinking in the language of proofs is proving difficult.&lt;/p&gt;
&lt;h3&gt;How do you go about tutoring?&lt;/h3&gt;
&lt;p&gt;For the introductory sessions that happened this week, my main goal was to get to know the tutees and understand where each of them was struggling by watching them work through practice problems. I don’t have a rigorous classification system yet, but this exercise was helpful for me and I hope for the tutees as well to get immediate feedback on some of their problems.&lt;/p&gt;
&lt;p&gt;I anticipate that the Tuesday sessions will be fairly productive because homework is assigned and due every Wednesay, so the three tutees I have then will bring plenty of questions to work on. I am allowed to help them with their homework directly (benefit of going to the official Student Academic Success Center!), only by leading them with directed questions and not flat-out giving them the answer, though.&lt;/p&gt;
&lt;h3&gt;I wanna be tutored by you!&lt;/h3&gt;
&lt;p&gt;sorry i’m too busy as it is :)&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Instead of these posts being daily, I’ll still try to make them weekly. The tag will still be “daily thoughts” because I want to keep all of these related posts in one category.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>Windows Development Adventures</title><link>https://www.hazelduvall.dev/blog/posts/2020-09-07-windows-development-adventures.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-09-07-windows-development-adventures.html</guid><pubDate>Mon, 07 Sep 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So one reason I’ve not updated this blog in a while has been school. Yeah I’ve been pretty
busy with homework already &amp;amp; classes &amp;amp; everything, but not really busy enough to not just
take 10 minutes out of my day to update.&lt;/p&gt;
&lt;p&gt;What really triggered me not posting was a project I’ve been working on. I was trying to
keep it a secret until “the big reveal” or whatever, but it’s just been taking &lt;em&gt;sooo longgg&lt;/em&gt;
that I had to make a post about it before I reveal a “final” (i.e. working, haven’t even
gotten there yet) product.&lt;/p&gt;
&lt;p&gt;In case you haven’t guessed from the title of the post, I am doing some pretty heavy
development for an application targeting the Windows operating system. I’m still keeping it
a secret (for absolutely no reason other than I enjoy keeping secrets), but the gist is that
it’s a large open source application whose Windows branch has been unmaintained since 2015.&lt;/p&gt;
&lt;p&gt;Things have changed quite a bit since 2015. It’s no longer reasonable to use Visual Studio
2013 to build your application. Windows DDK has turned into WDK and merged with the Windows
SDK. The whole concept of drivers has changed (slightly), and the whole build process has
changed dramatically. I am somewhat shocked that the extremely messy recursive NTMakefile
setup still works, was more shocked when most of the non-OS-specific parts of the
application built correctly with minimal additions (mostly to resolve merge conflicts that
I created when I merged the latest branch in with the most recent Windows branch). Like, if
you haven’t seen the code, you don’t know how amazing that is: it’s a lot of hot garbage
anachronisms and crazy design patterns and hacks upon hacks that it’s a miracle it compiles,
and I dearly hope it runs too (although that may be hoping beyond hope).&lt;/p&gt;
&lt;p&gt;I was brought back to earth when I realized the Windows-specific parts of the application
required some serious mantinence. There were uses of outdated APIs galore, a really funky
custom DLL loading system (that they really just should’ve used &lt;code&gt;.lib&lt;/code&gt; files for, like c’mon
that’s literally what those are made for), badly written NTMakefiles, and to top it all off,
at least 3 drivers written for a build system last supported in 2013. It’s &lt;em&gt;so old&lt;/em&gt; that
&lt;strong&gt;&lt;em&gt;the tools to update from it literally do not exist anymore&lt;/em&gt;&lt;/strong&gt;. Unfortunately I only
found that out after reading &lt;a href=&quot;https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/projectupgradetool&quot;&gt;this page&lt;/a&gt;
which promises they do exist (no they don’t stop lying microsoft).&lt;/p&gt;
&lt;p&gt;Anyways, as a status update, I’ve converted one driver by hand to build with Visual Studio
2019 &lt;code&gt;.vcxproj&lt;/code&gt; files and I hope to get both &lt;a href=&quot;https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debug-universal-drivers---step-by-step-lab--echo-kernel-mode-&quot;&gt;setting up a computer to debug the driver&lt;/a&gt;
and &lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild?view=vs-2019&quot;&gt;compiling the driver using MSBuild&lt;/a&gt;
to work. Wish me luck so I may be free of this project I’ve already spent more than a week
on and is showing me very dark depths of Windows.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Windows</category></item><item><title>Last Day Before Fall 2020 Semester</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-30-last-day-before-school.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-30-last-day-before-school.html</guid><pubDate>Sun, 30 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“I feel sad, so I will resolve a 60-file merge conflict in OpenAFS.
I see no possible way this could fail to cheer me up.”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;me, to me&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;(yeah i don’t really know what I was thinking. I am feeling a little
anxious about tomorrow but hope that will go away when I start to
work on school more, maybe)&lt;/p&gt;</content:encoded><category>quote of the day</category><category>CMU</category></item><item><title>As to not be Silent on Current Events</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-28-as-to-not-be-silent.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-28-as-to-not-be-silent.html</guid><pubDate>Fri, 28 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Going to out and say it: I don’t like the current state of America. Trump is not a good
president, no matter now the Republican National Convention tried to spin it. As if it
wasn’t already hard enough to trust America as a nation outside America (see
&lt;a href=&quot;https://en.wikipedia.org/wiki/United_States_involvement_in_regime_change&quot;&gt;here&lt;/a&gt; for just a
small example) or a minority inside America (see the civil rights movement) Trump has
exacerbated the problem greatly by near-constantly lying to make himself look good and
anyone who disagrees with him look bad.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Of course, Trump isn’t the only thing I’d like to talk about here. I don’t know how many
more political articles I’ll write, but at least for now I’d like to lay out my current
ideology as well as stances on today’s hot topics.&lt;/p&gt;
&lt;p&gt;I apologize in advance for not citing enough sources; I’ll add links later if I remember to.&lt;/p&gt;
&lt;h2&gt;Overarching Ideology&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;All humans deserve to live a comfortable life. With the amount of technology we have,
there should be no physical reason why we can’t achieve this goal.&lt;/li&gt;
&lt;li&gt;A government’s primary purpose is to support all the people under it’s domain so that
(1) is fulfilled. Democratic, federal, tiered governments seem to be the best at this so
far.&lt;/li&gt;
&lt;li&gt;Market-based economic system assumptions are close enough to true in enough scenarios
that they should stay in use.&lt;/li&gt;
&lt;li&gt;A government’s secondary purpose is to control for the excesses of market-based economics,
especially with respect to the environment and (1).&lt;/li&gt;
&lt;li&gt;The scientific method of conducting experiments and collecting evidence and using good
statistics is the best way to understand truth.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Black Lives Matter&lt;/h2&gt;
&lt;p&gt;I whole-heartedly support their goal: ensuring that African-American and other minorities
can finally be treated as true equals to the white majority in this country. Decades of
economic and social prejudice stand in the way. I’m not sure what a solution is, and also
not entirely sure what I can do besides make sure I am aware of the struggle and provide
support as I see it in my everyday life. It feels like I should be more proactive but again,
I don’t think I’m in a position yet to do more.&lt;/p&gt;
&lt;h3&gt;Protests and Police Brutality&lt;/h3&gt;
&lt;p&gt;Over the past month or more, there have been many protests for a specific policy target of
BLM: the disproportionate use of force against minorities. George Floyd, arrested for
supposedly using a $20 counterfit bill, died after a police officer very harshly put him in
a hold with a knee on his kneck. Protests over his death caused more death at the hands of
police officers, and the situation keeps spiraling. The most recent death publicized was
that of Jacob Blake, shot 7 times in the back in front of his children for “resisting
arrest” while walking back to his car. These deaths sicken me to know that there are people
with so little regard for the life of others, often racistly.&lt;/p&gt;
&lt;p&gt;A rallying cry has been “defund the police.” The protest have seen a massive backlash by
the police, with many videos showing excessive use of teargas, pepper spray, rubber
bullets, and other “nonlethal” weapons that nontheless cause extreme discomfort. Reporters
have been teargasses and even arrested while following police instructions (one of the more
extreme videos I saw was an entire news team being slowly arrested while the camera was
still rolling on live television). These uses of force also disturbed me.&lt;/p&gt;
&lt;p&gt;I’m not sure if I advocate for fully defunding the police. I do think it is a very
reasonable suggestion to cut back on police budgets so they can’t afford Ferraris or
stockpile military-grade equipment. I also think treating the causes of crime via community
support effots is also an excellent plan. This is where my certainty stops, because I don’t
have enough information of the efficacy of community support programs or how much they cost
or what one would even look like. I am certain that the theory around policing needs to
change from “we are the only thing stopping criminals from taking over” to “how can we make
&lt;em&gt;everyone&lt;/em&gt; in our community feel safe and respected?”&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Ok that was enough for one post. In the next one like this, I’d like to tackle &lt;strong&gt;QAnon&lt;/strong&gt; or maybe &lt;strong&gt;free speech&lt;/strong&gt;. See ya then.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Politics</category></item><item><title>A Paper I Disagree With</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-25-a-paper-i-disagree-with.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-25-a-paper-i-disagree-with.html</guid><pubDate>Tue, 25 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A summary: the paper in question talks about the theory of programming, what causes programs to become “complex” and hard to maintain, and proposes solutions towards that end. I disagree with the paper’s premises about what constitues programs that are hard to reason about.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;The paper: &lt;a href=&quot;http://curtclifton.net/papers/MoseleyMarks06a.pdf&quot;&gt;Out of the Tar Pit&lt;/a&gt; by Ben Moseley and Peter Marks. For the optimal blog-reading experience, I recommend reading through section 7 before continuing below. It’s a bit of a stretch to call it a paper even though it has the same structure, it reads more like a blog post.&lt;/p&gt;
&lt;p&gt;What I took away from it was the following argument: current languages and programming methodologies create more “complexity” than is necessary to actually solve problems, and a certain method of “Functional Relational Programming” can alleviate much of that complexity.&lt;/p&gt;
&lt;p&gt;The authors are clearly biased in their argument. Just read this section on page 12 (emphasis preserved):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Power corrupts&lt;/strong&gt;
What we mean by this is that, in the absence of language
enforced guarantees (i.e. restrictions on the &lt;em&gt;power&lt;/em&gt; of the language)
mistakes (and abuses) &lt;em&gt;will&lt;/em&gt; happen. This is the reason that garbage
collection is good — the &lt;em&gt;power&lt;/em&gt; of manual memory management is
removed. Exactly the same principle applies to &lt;em&gt;state&lt;/em&gt; — another kind
of &lt;em&gt;power&lt;/em&gt;. In this case it means that we need to be very wary of any
language that even &lt;em&gt;permits&lt;/em&gt; state, regardless of how much it discourages
its use (obvious examples are ML and Scheme). The bottom line is
that the more &lt;em&gt;powerful&lt;/em&gt; a language (i.e. the more that is &lt;em&gt;possible&lt;/em&gt; within
the language), the harder it is to &lt;em&gt;understand&lt;/em&gt; systems constructed in it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a blatant attack on the most common systems language known to be responsible for large classes of bugs: (you already know what language I’m talking about) C and C++.&lt;/p&gt;
&lt;p&gt;Now, I do agree that the manual memory management done by C and C++ is horrible in terms of safety guarantees. However, I &lt;em&gt;very much disagree&lt;/em&gt; with the assertion that “state should be avoided at all costs.”&lt;/p&gt;
&lt;p&gt;The authors make a later claim about how allowing stateful code leads to complicated informal reasoning. On the contrary, I postulate that for many algorithms, a state-based approach makes the most sense. An example given in the CMU 2023 discord was the BFS algorithm. A traditional approach is as follows: use a stateful queue of (node, depth) items and a set of explored nodes. The queue and set woudl be initialized with the starting node. While there are nodes in the queue, pop a node, add it to the explored set, and push all unexplored neighbors back on the queue. This &lt;em&gt;makes sense to me&lt;/em&gt; and many other programmers used to thinking imperatively. Heck, I’d argue that, with explanation of the motivation behind the algorithm, it would make sense to non-programmers as well.&lt;/p&gt;
&lt;p&gt;Now consider the functional approach. You either have an unreadable mess like&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://www.hazelduvall.dev/static/unreadable-fp-mess.png&quot; alt=&quot;A very strange implementation of BFS&quot; /&gt;&lt;/figure&gt;
&lt;p&gt;… or you end up re-implementing a mutable state with immutable arguments and a tail-recursive function.&lt;/p&gt;
&lt;p&gt;Now, this is just one example. I concede that there are many other algorithms better implemented in a functional style. That doesn’t necessarily mean we should restrict the language we program in to be nigh-unusable as to guarantee safety. Performance is important too, although nowadays less micro-optimizations (those are better taken care of by a smart compiler or library authors) and more algorithm design. If you can’t write a smart algorithm due to restrictions by the language, then the benefits of safety are less clear (to me).&lt;/p&gt;
&lt;p&gt;In any case, I don’t think the authors are necessarily concerned with performance at all, and consider it a secondary goal at best, as evidenced by the following quotes (page 27):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is worth noting that because typically the informal requirements will
not mention concurrency, that too is normally of an accidental nature. In
an ideal world we can assume that finite (stateless) computations take zero
time and as such it is immaterial to a user whether they happen in sequence
or in parallel.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(page 36):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is worth noting in particular the risks of “designing for performance”.
The dangers of “premature optimisation” are as real as ever — there can
be no comparison between the diculty of improving the performance of a
slow system designed for simplicity and that of removing complexity from a
complex system which was designed to be fast (and quite possibly isn’t even
that because of myriad ineciencies hiding within its complexity).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I agree with the second more than the first, but my point still is that the types of languages the authors advocate for (Functional Programming, Logic Programming) and the types of language constructs they wish to minimize (if statements, loops, stateful behavior) by themselves will not lead to better code. It might make code that’s easier for mathematicians to reason about and prove “correctness” of, whatever that means, but it will not make the code simpler by any margin.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Another key point I’d like to make before I wrap this up: Functional and Logic programming do not capture they way that computers operate in the same way that Imperative programming does. This might be a niche view, but I believe it &lt;em&gt;is necessary&lt;/em&gt; to understand how computers work if one wishes to program them. That view seems to have persisted in computer science education thus far, where imperative languages are taught to beginners, probably as a remnant of when programming was more of an engineering discipline.&lt;/p&gt;
&lt;p&gt;Having been exposed to Functional Programming, I think that knowledge of its techniques are sorely needed in computer science education. Writing safe, provable, understandable code is a worthy goal. I remain unconvinced that the “Functional Relational Approach” is the best way to go about this.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;In case you haven’t had enough of Functional Programming shills spouting techical jargon at you, just read &lt;a href=&quot;https://en.wikipedia.org/wiki/Monad_(functional_programming)&quot;&gt;the Wikipedia article on Monads&lt;/a&gt;. I mean seriously, who thought this was a a good explanation for people who don’t understand it already?&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Cool Videogame: Skullgirls</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-22-skullgirls.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-22-skullgirls.html</guid><pubDate>Sat, 22 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here’s a videogame I’ve been playing a lot recently: &lt;a href=&quot;https://skullgirls.com/&quot;&gt;Skullgirls&lt;/a&gt;
(warning: some of the characters have… questionable clothing, so only click the link if
you are not at work).&lt;/p&gt;
&lt;p&gt;It’s the first fighting game I’ve played, and as it turns out it’s actually very beginner
friendly. The tutorial is set up to bring you from knowing nothing about the game into being
fairly ok. Some of the harder tutorials require a lot of grinding (looking you at 3-4 and
4-7) but are so worth it for knowing how to do the timing for more compilcated combos.&lt;/p&gt;
&lt;p&gt;As of now, I’ve completed the entire beginner tutorial and two of the character-specific
combo tutorials for Filia and Big Band. I am still nowhere near the level needed to compete
online, however. I’ve also watched a lot of professional gameplay and studied other game
techniques.&lt;/p&gt;
&lt;p&gt;The most other effort I’ve put into a game like this have been for (&lt;em&gt;checks Steam library&lt;/em&gt;)
&lt;a href=&quot;https://www.kerbalspaceprogram.com&quot;&gt;Kerbal Space Program&lt;/a&gt;,
&lt;a href=&quot;https://www.factorio.com&quot;&gt;Factorio&lt;/a&gt;, and
&lt;a href=&quot;https://www.smashbros.com/en_GB&quot;&gt;Super Smash Brothers Ultimate&lt;/a&gt;. This sort of reflects my
changing tastes through the years, moving from building games to fighting games, but I still
do like those old games and no longer play them kinda only because I’m a little worn out
from them.&lt;/p&gt;
&lt;p&gt;One of my friends also plays Skullgirls, although he’s not quite as into it as I am. I think
it’s good to have a hobby that’s purely for fun to enjoy with friends, even if most of my
time spent on it is improving my own skills in training mode instead of playing online. I
hope to find more people at CMU that also enjoy fighting games and potentially get good with
people at &lt;a href=&quot;https://www.arcsystemworks.jp/guiltygear/en/&quot;&gt;Guilty Gear Strive&lt;/a&gt; once that
releases.&lt;/p&gt;
&lt;p&gt;Anyways I didn’t write about Hakyll this time, that’s because I worked on another
programming project today. I think I’ll post about that tomorrow. See you then&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Upcoming College Semester Plans</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-21-college-stuff.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-21-college-stuff.html</guid><pubDate>Fri, 21 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So, as you may know from the &lt;a href=&quot;/about.html&quot;&gt;about page&lt;/a&gt;, I am starting my sophomore year at
Carnegie Mellon University this fall. As you may have guesses from the context of this post
and the state of the world in general, this semester will be entirely online.&lt;/p&gt;
&lt;p&gt;It’s not all bad. I get to stay with my very nice family (who were very cooperative during my
work from home for Aerospace) and eat good meals and be in a house nicer than a college dorm
and have a car and dogs. However, I do lose the in-person experience of hanging out with fellow
college students &amp;amp; teachers.&lt;/p&gt;
&lt;p&gt;The scales there are definetly tiped towards appreciating my current situation, but I do
sincerely miss spontaneous interactions with friends. Don’t tell anyone but there were two girls
I was trying to get to know better and it might be awkward to just pick it up again with them
after all this time but idk, I’ve never done stuff like this before.&lt;/p&gt;
&lt;p&gt;Anyways enough virgin-ranting and more talking about real Plans, the title of this post.&lt;/p&gt;
&lt;p&gt;I’m taking 5 classes (~50hours/week), working part-time (~5hours/week) as a university tutor,
and also working part-time at Aerospace (~5hours/week).&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://www.hazelduvall.dev/static/fall2020-schedule.jpeg&quot; alt=&quot;Image my fall 2020 schedule&quot; /&gt;&lt;figcaption&gt;Funky schedule? &lt;s&gt;Leave your thoughts down in the comments, make sure to like and subscribe!&lt;/s&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Oh yeah and I also plan to keep working out &amp;amp; doing any other hobbies that keep me sane.
So my work’s cut out for me, that’s for sure. I’ll definitely have more to say about that once
it all gets going.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>Haskell Packages are Pretty Ok and Other Ramblings</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-20-haskell-packages.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-20-haskell-packages.html</guid><pubDate>Thu, 20 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After writing the code for &lt;a href=&quot;./2020-08-19-hacking-on-hakyll.html&quot;&gt;my previous blog
post&lt;/a&gt;, today I put it into a separate
Haskell package so my code doesn’t smell too bad anymore.&lt;/p&gt;
&lt;p&gt;I also fixed a small CSS error that caused the font size on mobile to be waay
too big. Forgot the &lt;code&gt;.&lt;/code&gt; in &lt;code&gt;1.8rem&lt;/code&gt; *facepalm*.&lt;/p&gt;
&lt;p&gt;Oh yeah I also installed a LaTeX package so now I can do cool stuff like&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;f(x)=1−x2f(x) = \sqrt{1-x^2}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;while writing these posts. Which will hopefully be useful in the future as I
talk about math at school more although I don’t know how much I’ll be able to
post then as I have both a heavy course load and two small part-time jobs that
add up to a fairly substantial part-time job.&lt;/p&gt;
&lt;p&gt;Also you might be thinking, “Hazel you have only posted about this darn blog for
the last &lt;code&gt;n&lt;/code&gt; days, isn’t it time to write about something else??” To which I
say, yes, you are absolutely correct, it’s just that I usually write these posts
right after working on the code for the site generator so that’s usually what
I’m thinking about at the time lol. We’ll see what happens after I stop work on
the backend and actually get to a “post grind” lol&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Hakyll</category><category>Web</category></item><item><title>Hacking on Hakyll for better Pages</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-19-hacking-on-hakyll.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-19-hacking-on-hakyll.html</guid><pubDate>Wed, 19 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In case you are one of the few people who know about this blog, you might have
noticed that I changed from titles of posts as the HTML filenames to just the
“post ID” as the filename. This may not seem like a big change, but oh boy did
Hakyll require some funky upgrades to get it to work.&lt;/p&gt;
&lt;p&gt;Basically, I re-implemented &lt;a href=&quot;https://jaspervdj.be/hakyll/reference/Hakyll-Web-Paginate.html&quot;&gt;Hakyll.Web.Paginate&lt;/a&gt;,
but with logic customized for single pages instead of pages that are actually
groups of other pages. I also added title metadata extraction instead of just
page number + url extraction to the context creator for extra fanciness.&lt;/p&gt;
&lt;p&gt;The backend is messy, but in the end it turns out very nice and “declarative”
whatever that means:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;    pages &lt;/span&gt;&lt;span&gt;&amp;lt;-&lt;/span&gt;&lt;span&gt; buildPagesWith &lt;/span&gt;&lt;span&gt;&quot;posts/*&quot;&lt;/span&gt;&lt;span&gt; sortChronological&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    pageRules pages &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;span&gt;index _ &lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      route &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; pageIndexRoute index&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      compile &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        let&lt;/span&gt;&lt;span&gt; fullPostCtx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; pageContext pages index &lt;/span&gt;&lt;span&gt;`mappend`&lt;/span&gt;&lt;span&gt; postCtxWithTags&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        pandocCompiler&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          &amp;gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; loadAndApplyTemplate &lt;/span&gt;&lt;span&gt;&quot;templates/post.html&quot;&lt;/span&gt;&lt;span&gt;    fullPostCtx&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          &amp;gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; loadAndApplyTemplate &lt;/span&gt;&lt;span&gt;&quot;templates/default.html&quot;&lt;/span&gt;&lt;span&gt; defaultContext&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          &amp;gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; relativizeUrls&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not to be content with that small victory, I also added pages to &lt;a href=&quot;/blog/archive.html&quot;&gt;the archive&lt;/a&gt;
with Hakyll’s original &lt;code&gt;Paginate&lt;/code&gt; thingy, also adding title support on top of
that. Again it was really messy but also really worth it.&lt;/p&gt;
&lt;p&gt;Anyways I am really getting my value out of Hakyll for both reasons: I’m having
a very snappy blog (static sites &amp;gt;&amp;gt;&amp;gt; Wordpress any day) and I’m also learning
Haskell fairly quickly which is neat. Tomorrow I will probably reorganize my
code into better-named modules, but for now I’m happy.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Hakyll</category></item><item><title>Haskell Takes Way Too Long To Compile</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-18-haskell-takes-way-too-long-to-compile.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-18-haskell-takes-way-too-long-to-compile.html</guid><pubDate>Tue, 18 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow that was rough.&lt;/p&gt;
&lt;p&gt;I left a &lt;code&gt;stack build&lt;/code&gt; command running overnight on the machine I was planning to host this static
site from, and apparently the Haskell compiler just needs exorbitant amounts of memory to operate
properly. I mean to be fair running two compilers at once with only 2GB memory available is bound
to cause &lt;em&gt;some&lt;/em&gt; problems sure but not “your system is literally dying and can no longer handle
network interrupts” levels.&lt;/p&gt;
&lt;p&gt;I was able to fix the problem by compiling the &lt;code&gt;Cabal&lt;/code&gt; and &lt;code&gt;pandoc&lt;/code&gt; packages individually, because
both on their own were using the full 2GB and really did not like being run at the same time. It
was running overnight (15 hours) and still didn’t finish.&lt;/p&gt;
&lt;p&gt;In the end I still spent 4 hours compiling stuff. Was that worth it? remains to be seen. but now
there’s a blog so i guess so&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Hakyll</category></item><item><title>Blog Theme Upgrades!</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-17-hakyll-upgrades.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-17-hakyll-upgrades.html</guid><pubDate>Mon, 17 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow the blog sure looks snazzy now! I ripped the twenty-fifteen theme from
Wordpress and applied it to my new Hakyll blog and tweaked it a little and
now it looks pretty nice if I do say so myself. I’m sure I’ll find more ways to
tweak it, but for today I am done.&lt;/p&gt;
&lt;p&gt;Also I’ve been doing art more so maybe I’ll have a piece to post here one day?
Who knows. anyways I need to find a place to host this soon so ppl can actually
see the improvements and content instead of just me. Although I am running this
blog just for me anyways. idk we’ll see.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Hakyll</category><category>Web</category></item><item><title>Blog is now on Hakyll</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-15-hakyll.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-15-hakyll.html</guid><pubDate>Sat, 15 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi! This site looks a little different how. Just for fun, I’d thought I’d move
away from Wordpress (MySQL is very slow and PHP is not a great language and also
Wordpress itself has a bunch of vulnerabilities) and towards a static site.&lt;/p&gt;
&lt;p&gt;As you may have guessed from the title of this post, I’m using a system called
&lt;a href=&quot;http://jaspervdj.be/hakyll&quot;&gt;Hakyll&lt;/a&gt; to make it. Hakyll is written in Haskell
which is one of the worst language’s I’ve had the pleasure of working with. It
was a challenge to get the &lt;a href=&quot;/blog/tags.html&quot;&gt;tags section&lt;/a&gt; customizable, among many
other issues I had with learning Haskell in general.&lt;/p&gt;
&lt;p&gt;Also, I’m still doing art! I have improved a lot but still not enough to the
point where I’d feel comfortable cross-posting to something else here. Maybe
one day I’ll muster up the courage to put some of my figure drawings here.&lt;/p&gt;
&lt;p&gt;Oh yeah also Coronavirus, crazy right? Don’t worry I’ll have a post about that soon.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>Hakyll</category><category>Web</category></item><item><title>I&apos;m actually working now</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-06-im-actually-working-now.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-06-im-actually-working-now.html</guid><pubDate>Thu, 06 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was lucky enough that my summer internship let me work remote. I am double lucky that they’re going to let me work part-time during the school year. Great company, great managers + co-workers, and I get to do AI research. So far, this is pretty much everything I wanted in a job!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>P-values are wack</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-02-p-values-are-wack.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-02-p-values-are-wack.html</guid><pubDate>Sun, 02 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Like look at this: &lt;a href=&quot;https://en.wikipedia.org/wiki/P-value#Calculation&quot;&gt;https://en.wikipedia.org/wiki/P-value#Calculation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Literally just “plug your data into a formula and get out a p” how crazy is that? Really I can only make sense of &lt;a href=&quot;https://en.wikipedia.org/wiki/Fisher%27s_exact_test&quot;&gt;https://en.wikipedia.org/wiki/Fisher%27s_exact_test&lt;/a&gt; but even that’s a little tough to understand. Maybe I just need to study statistics more…&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>I&apos;m back baby</title><link>https://www.hazelduvall.dev/blog/posts/2020-08-01-im-back-baby.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2020-08-01-im-back-baby.html</guid><pubDate>Sat, 01 Aug 2020 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow, a lot sure has happened since I went to college and stopped updating this blog! Going to college meant I couldn’t leave my old laptop plugged in and constantly hosting on a free domain like before (sad), but now I re-discovered that my high school has free hosting (yay)! So I exported my blog here, where it will stay until I get kicked off and have to pay for hosting somewhere else. Thank goodness Wordpress is a stable piece of software.&lt;/p&gt;
&lt;p&gt;Hopefully in the coming few days I remember to post more frequently again. I have a couple cool projects to show since last year ;) Stay fresh, anyone reading this!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 14</title><link>https://www.hazelduvall.dev/blog/posts/2019-08-14-qotd-14.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-08-14-qotd-14.html</guid><pubDate>Wed, 14 Aug 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“Guess this is the last time I’ll see you for a while, huh?”&lt;/p&gt;
&lt;p&gt;-My friend, tonight, at our last get-together before college&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(I’m so sad but literally nearly everyone I know my age is going through the same thing, so at least I’m not too alone in that)&lt;/p&gt;</content:encoded><category>quote of the day</category></item><item><title>Going to College</title><link>https://www.hazelduvall.dev/blog/posts/2019-08-14-going-to-college.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-08-14-going-to-college.html</guid><pubDate>Wed, 14 Aug 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hey so sorry I haven’t posted lately. There’s been a lot on my mind but as
usual I’ve been too lazy and out of habit to write any of it down here. So
here’s a few snippets of recent thoughts before I head into the main topic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I got my custom allocator to work, and submitted the resulting program to
CodeGolf.stackexchange.com for a sweet-ish +60 rep&lt;/li&gt;
&lt;li&gt;I did a little PicoCTF as warmup for (hopefully) meeting the Plaid
Parliament of Pwning @ orientation week&lt;/li&gt;
&lt;li&gt;8chan in the news over being shut down, I think it’s sort of scary that free
speech can be suppressed on the internet but at the same time find it
totally justifiable to kick them off. Main thought: “No one is entitled to
let you use their property (servers) to express hateful speech that would be
prosecuted even in a public space.”&lt;/li&gt;
&lt;li&gt;I’m walking a neighbor’s dog while they’re on vacation, a golden retriever
that is on the down slope of aging and very needy with wanting to sniff.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So now that that’s out of the way, let’s move on to what I think about going to
college: I just want to get it over with. The last thing I wanted with this
whole process was some sort of limbo where I feel like half there and half
here. I would have preferred to do it in one day, like &lt;em&gt;snap&lt;/em&gt; and I go from
being here and comfortable to being there and not exactly comfortable but
getting used to the place. I know that sounds silly but one can hope. Instead,
the feeling of “last time I’ll do this for a while” just keeps lingering and
lingering and it’s hard to stand it, so I just avoid thinking about it like a
dumbbutt. I still need to pack a few things, most notably all the stuff I love
on my desk. And even when that’s away it’ll still be a few days until I’m
actually fully unpacking it.&lt;/p&gt;
&lt;p&gt;Dang nabbit I just want to be there already. I want to think about making
friends and walking to classes and having lunch and living in my own instead of
packing and photocopying forms and yeckh this is a total #whitepersonproblen
because a whole load of people would kill to go to this college and have to
opportunities I have, and instead I’m complaining about it like a looser. I
just want to be there already. That’s too much to ask.&lt;/p&gt;</content:encoded><category>daily thoughts</category><category>CMU</category></item><item><title>Programming a Custom Memory Allocator</title><link>https://www.hazelduvall.dev/blog/posts/2019-08-06-programming-a-custom-memory-allocator.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-08-06-programming-a-custom-memory-allocator.html</guid><pubDate>Tue, 06 Aug 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Uh, it’s super hard and I failed in the 2 hours I gave myself. The basic idea was this: keep track of the current block of memory, its size, and the index. If the index ever goes out of bounds, allocate a new block twice the size of the current one and copy everything over to that.&lt;/p&gt;
&lt;p&gt;I first encountered a double-free error. Just wanting to get something to work, I commented out the code that freed the old buffer knowing full well that would cause a memory leak. No dice, now we have a use-after-free. No problem, silly me, I forgot to change the pointers within the data (lots of linked lists), so I’ll just calculate the offset and add it to everything. Still nothing and now we’re back to the double-free. I honestly have no idea what I did wrong but maybe it’ll be clearer in the morning. If I can’t figure it out soon, I’ll just go to keeping track of all the malloc-ed memory in another art and free that iteratively (I was getting a stack overflow error when trying to free it recursively, which was why I build the allocator in the first place).&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Visualizing Perspective</title><link>https://www.hazelduvall.dev/blog/posts/2019-08-04-visualizing-perspective.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-08-04-visualizing-perspective.html</guid><pubDate>Sun, 04 Aug 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So here’s an excercise for you reader: picture a cube with a face flat towards you. Got it? Ok, now rotate it 30 degrees about the up-down axis (could be y or z depending on which you’re more used to). Can you still clearly see the cube? Ok, now rotate that already rotated cube 15 degrees around the left-right axis. Can you still picture what the cube looks like?&lt;/p&gt;
&lt;p&gt;See, here’s the thing: I can’t. Even after one rotation I have trouble focusing on exactly what the cube looks like in my mind’s eye. Two rotations and it’s really game over. Logically, I can understand there has to be a small kite, a medium kite, and a larger kite (from geometry, a kite is defined as a quadrilateral with two pairs of adjacent equal length sides), and I know where those shapes are, but for the life of me I can’t visualize what they look like put together. It’s like I hit a mental roadblock. It’s annoying.&lt;/p&gt;
&lt;p&gt;I’ve been thinking about that for a while, how my intuition about 3D space doesn’t translate well into drawing it. Because I’ve been having trouble with it, I challenged myself to do an art piece with a cool perspective effect. It’s hit-or-miss so far, but I’ll keep at it.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Pokémon</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-31-pokemon.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-31-pokemon.html</guid><pubDate>Wed, 31 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Me and Pokémon, like any child of my generation, or the previous, go waaaay back. My first real video game that I remember is Pokémon Pearl (which I will forever consider to be the purest, most natural form of Pokémon games). I will never forget the exhilaration of besting the elite four and champion for the first time with the team that I had grown so close to while training. One of my favorite Saturday morning cartoons was Pokémon, and our family even bought the Pokémon DVD movies for us to watch in the car on road trips.&lt;/p&gt;
&lt;p&gt;Pokémon has awesome monster with cool attacks, so it appeals to little boys. Pokémon has a good message and doesn’t show explicit violence, so it appeals to parents. Anyone can adore the cutest Pokémon. As a franchise, Pokémon has consistently pulled off the collectible RPG battler so, so well. Any deviations from the formula are met with resistance (Pokémon GO), although some are improvements (the move to 3D).&lt;/p&gt;
&lt;p&gt;I always admire how Nintendo and Game freak are able to keep the same core game so fresh by adding new worlds and creatures and people all the time.  There have been a few complaints about the direction the games are heading in (too linear, designs are too cutesy and have deviated from the “realism” of the original entry) but overall I believe Pokémon will stay good. It already is a global force of pop culture, and I hope it will stay that way for generations to come.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Staying up late (again)</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-30-staying-up-late-again.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-30-staying-up-late-again.html</guid><pubDate>Tue, 30 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So one reason I haven’t been posting as often is that I’ve kinda fallen out of the routine of it. Why? Because my daily routine has changed.&lt;/p&gt;
&lt;p&gt;Recently, I’ve been streaming art for longer, and starting later, pushing logoff time to 10:30PM to even 11:30PM. This is not good. The reason for going longer is obvious: the 1 hour limit I was struggling to hit earlier is now a breeze because I feel comfortable doing art for longer now. The reason for starting later is less obvious: my sister and I now watch anime together every night, cutting in to the 9PM start I aim for. As a result, I feel less inclined than before to stay up later thinking and writing “deep” thoughts on my phone like I used to just a few weeks ago.&lt;/p&gt;
&lt;p&gt;I love summer in all the freedom of time it provides, but I really need to get my sleep schedule back of track.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>screw you too, respondus</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-27-screw-you-too-respondus-copy.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-27-screw-you-too-respondus-copy.html</guid><pubDate>Sat, 27 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;figure&gt;
&lt;img alt=&quot;Running LockDownBrowser inside a VM&quot; src=&quot;https://www.hazelduvall.dev/static/screw-you-too-respondus-Copy.png&quot; /&gt;
&lt;/figure&gt;</content:encoded><category/></item><item><title>Beating Respondus LockDown Browser</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-27-200-autosave-v1.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-27-200-autosave-v1.html</guid><pubDate>Sat, 27 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It was actually easier than I thought. Now, it wasn’t the easiest, but I will explain what I tried and what worked.&lt;/p&gt;
&lt;p&gt;So Respondus LockDown is the browser my school forces us to use to take “secure” online exams. I hate it. I despise it strongly. Everything it stands for, the institutionalized test-taking mentality, the enforcement of unrealistic conditions, the distrust of students most of all, it ticks me off to my core. So I did something about it. I “hacked” their stupid browser that fullscreens itself, disables all other applications, limits the input options, and watches your every move with your webcam.&lt;/p&gt;
&lt;p&gt;There were two ways of going about it: the first and most flexible option is to run LockDown in a VM. The other option would be to MITM myself to have an &amp;lt;iframe&amp;gt; of google constantly beside the test. The second has the disadvantage of more easily being caught (screenshots and keylogging, duh), and being more work for me. Also I didn’t want to ever install that piece of malware on my actual computer. So I went with the first option.&lt;/p&gt;
&lt;p&gt;I spent many hours researching VM detection techniques and their associated bypasses, accumulating in finding and understanding a github repo that generated scripts to hide the fact that a VM is a VM. The one I used is located here: &lt;a href=&quot;https://github.com/nsmfoo/antivmdetection&quot;&gt;antivmdetection&lt;/a&gt;. I first tested LockDown in a untouched Windows VM, and sure enough it knew. So I ran the scripts, and voila it worked. What the scripts did was change all the VirtualBox device driver names, like the BIOS model, the video card name, the hard drive serial number, etc. to the exact same ones as my host computer. It changes those through VirtualBox settings and through registry editing. There’s also a neat trick with the &lt;code&gt;cpuid&lt;/code&gt; instruction that’s &lt;a href=&quot;https://rayanfam.com/topics/defeating-malware-anti-vm-techniques-cpuid-based-instructions/&quot;&gt;explained much better here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Other approaches that I tried in the VM but couldn’t get to work were using a sandbox (LockDown didn’t like the sandbox management program running) and disassembling and editing the LockDown binary (I was just bad at that tho lol).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT!&lt;/strong&gt; please note that I did this only as an experiment to see if I could because I was mad, I do not intend to use this to cheat and I will take all my exams in the correct fashion, with LockDown installed on my main computer.&lt;/p&gt;</content:encoded><category>projects</category></item><item><title>Being rushed</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-23-being-rushed.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-23-being-rushed.html</guid><pubDate>Tue, 23 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I don’t really like it. Other people sometimes do better under pressure, but not me. I like to do things at my own pace, way in advance, so I’m fully ready when the time comes.&lt;/p&gt;
&lt;p&gt;Which is odd when paired with another of my tendencies: to be terrible and managing long-term deadlines. If it’s not in the next week and/or I don’t care about it, it won’t get done until I’m prodded. I consciously try to counteract that because it’s a bad habit.&lt;/p&gt;
&lt;p&gt;With deadlines I do care about, however, I get stuff done right away, early like mentioned earlier. Like in &lt;a href=&quot;https://www.thunderbird.net/en-US/&quot;&gt;Thunderbird&lt;/a&gt;, I do now have a calendar to keep track of the stuff I don’t care about, and I try to check it daily. We’ll see how that works out in college.&lt;/p&gt;
&lt;p&gt;Oh also I got terrible course scheduling for college, I did it way to late so all the good time slots were filled, shoot. I was bad with managing that deadline, I really shouldn’t have been…&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 13</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-22-qotd-13.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-22-qotd-13.html</guid><pubDate>Mon, 22 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“I fear for the future of your Twitter/DeviantArt account.”&lt;/p&gt;
&lt;p&gt;-My friend after I told him my secret to getting motivated at art.
(hint: it’s not spite)&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>Haven&apos;t shaved</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-22-havent-shaved.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-22-havent-shaved.html</guid><pubDate>Mon, 22 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;…my stubble for like 3 days now. Man do I look scraggly. It’s also itchy. I don’t know how people with beards do it.&lt;/p&gt;
&lt;p&gt;Honestly, shaving every morning isn’t even that hard. It takes 2 min max and gives good results for the effort put in. Maybe not the best results, because a 5’oclock shadow is a real thing (hair grows back!) but good enough.&lt;/p&gt;
&lt;p&gt;I don’t know where I’m going with this, other than having a full, professional-looking beard is probably even more work to maintain than a clean shave. I wouldn’t know. I don’t plan on findings out either, definitely shavings tomorrow morning.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Past 10PM</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-21-past-10pm.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-21-past-10pm.html</guid><pubDate>Sun, 21 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After I’m supposed to go to sleep, but am still awake, I turn into a different person.
I’m more outgoing. I care lesss about long-term repercussions. I slur my words more.
I’m crazy and conscious of it yet I love it and can’t stop. No, I’m not implying
that I drink alcohol (hate the stuff) or do any other sort of drug at night.
No, the night &lt;em&gt;is&lt;/em&gt; my drug.&lt;/p&gt;
&lt;p&gt;So anyways that’s how I just confessed I was horny while writing this post. Blehck.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Edgy Jokes</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-20-edgy-jokes.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-20-edgy-jokes.html</guid><pubDate>Sat, 20 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;They’re good when they’re done right, but absolutely awful when done wrong. My friends and I got together and the group tendency leaned toward the edgier side while playing the Jackbox party game, so we got to see the whole spectrum.&lt;/p&gt;
&lt;p&gt;A good edgy joke makes you think. It’s not edgy for edginesses sake (although it can be made with that in mind), it’s edgy in a way that makes you question your preconceived notions about the world. Take the winner of the TeeKO game. It was a simply draw, smiling potted flower with the caption, “Big Brother is watching.” By incorporating a pop culture reference about government and now corporate surveillance of the masses with the kind of cute, childlike imagery used to masquerade or deflect questions about the massively trove of data being amassed on every citizen, the shirt design spoke perfectly to our woke teenage brains.&lt;/p&gt;
&lt;p&gt;A bad edgy joke told later that night was during Fibbage, when someone made a crude reference to slavery. It was not well put together, didn’t twist the viewers’ expectations in any meaningful way (can hardly be called a joke if it doesn’t do that), and could even be interpreted as complicit with the abhorrent practice.&lt;/p&gt;
&lt;p&gt;Finding the right balance between joking about something and being deadly serious about the issue is the essence of an influential edgy joke. At least that’s my opinion. This whole post is kind of a joke in and of itself, but I Don’t Care.&lt;/p&gt;
&lt;p&gt;(Anyways update in the Visual Studio thing: after 3 more hours, got it to reliably compile! Yay now I can start actually developing.)&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Visual Studio was never meant to be used with CMake</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-18-visual-studio-was-never-meant-to-be-used-with-cmake.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-18-visual-studio-was-never-meant-to-be-used-with-cmake.html</guid><pubDate>Thu, 18 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today I was locked in bloody struggle with CMake + Visual Studio, trying to get a small-ish open source project to compile. After 3 hours of non-stop effort, I can say that I have been defeated for now but am not giving up hope. I got past all the stupid cmake errors and the stupid dependency errors but am stuck on a stupid linking error (seriously? Why is it trying to link to a binary that I never told it to? &lt;strong&gt;and whose name is only slightly different from the one it should link to?&lt;/strong&gt;)&lt;/p&gt;
&lt;p&gt;It could be worse. At least this software was meant to be built on Windows with MSVC. And has a binary release in case I give up. But I won’t. Probably.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Is Metacognition Smart?</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-17-is-metacognition-smart.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-17-is-metacognition-smart.html</guid><pubDate>Wed, 17 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Metacognition (n): Thinking about  how you think.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First answer: maybe. Why? The weak argument of: I seem to be smart enough, I practice metacognition, ergo. Unless I conduct a metacognition study, I’ll have to be satisfied with a sample size of n=1.&lt;/p&gt;
&lt;p&gt;Second answer: maybe not. Why? Because, can higher level thought processes really change the deeper ones that control how we think? My opinion is, once you get going down a certain way, it’s really hard to get off that train of thought. My (yes, limited,  thanks for noticing adult me) experiences show that only other experiences can actually change how your brain works and make it smarter. It’s very hard to imagine any new way of thinking until you absorb an idea or emotion externally. (Well then how do people come up with new ideas? Slowly and with lots of synthesis from old ideas).&lt;/p&gt;
&lt;p&gt;Or, maybe, I still don’t understand enough about how I think for metacognition to be useful for me yet. Come to think of it, thinking about math or computer science or English were all just another skill that I got better at by repeated, structured practice. An actual philosophy/psychology course is in order, then? I’ll think about it.&lt;/p&gt;
&lt;p&gt;Anyways sorry for the rambly post, I kept thinking of new things half-coherently in the middle of writing. It feels good to write down these (mostly stupid) ideas sometimes, even if no one else reads them.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 12</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-16-qotd-12.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-16-qotd-12.html</guid><pubDate>Tue, 16 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“OMIGOSH me too!”&lt;/p&gt;
&lt;p&gt;-Cute girl at the mall
(We met in the bookstore near the graphic novel section, sharing an interest. I rode the high of mutual flirtation for a solid 2 hours. Still thinking about it. What is wrong with me)&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>Operating System Shopping (2/2)</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-16-operating-system-shopping-2-2.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-16-operating-system-shopping-2-2.html</guid><pubDate>Tue, 16 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Previously: &lt;a href=&quot;./2019-07-15-operating-system-shopping-1-2.html&quot;&gt;Operating System Shopping
(1/2)&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So, where I left of was, there are a lot of &lt;strong&gt;bad&lt;/strong&gt; things about all of today’s popular operating system kernels. Let’s just roll through the list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows: pile of legacy garbage.&lt;/li&gt;
&lt;li&gt;XNU: unusable except in MacOS, which is a walled garden nearly impossible to install on non-Apple hardware.&lt;/li&gt;
&lt;li&gt;Linux: wacky monolithic kernel, very little inter-distro compatibility, little focus on usability for users.&lt;/li&gt;
&lt;li&gt;BSD: like Linux but with even less hardware support.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Really, what I would like to see is a viable &lt;a href=&quot;https://en.wikipedia.org/wiki/Microkernel&quot;&gt;Microkernel&lt;/a&gt; that can be used to run a functional desktop, but that’s currently beyond today’s development. Turns out all the inter-process communication they require is a big hit to performance, even if it’s also a win for security, so people just haven’t developed them as much. A look at the current contenders:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GNU Hurd: promising, development stalled but might get back up soon, but it’s GNU.&lt;/li&gt;
&lt;li&gt;MINIX: probably has no hardware support for anything made this decade.&lt;/li&gt;
&lt;li&gt;Plan 9: I’m not trying to run a distributed OS&lt;/li&gt;
&lt;li&gt;Haiku: might actually be the most functional of this bunch, but still missing a lot of tools[citation needed]&lt;/li&gt;
&lt;li&gt;Redox: super promising (I adore it’s “everything is a URL” scheme), but isn’t even self-hosting yet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ok so it’s easy to point out the bad. Now what about the good?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows: &lt;strong&gt;can&lt;/strong&gt; actually run legacy applications with ABI compatibility, unlike most -NIXes.&lt;/li&gt;
&lt;li&gt;MacOS: UNIX + commercial success and support = greatness&lt;/li&gt;
&lt;li&gt;Linux: very performant, perfect for servers, you are very hard pressed to &lt;em&gt;not&lt;/em&gt; use it as your development OS if you’re doing research.&lt;/li&gt;
&lt;li&gt;BSD: very stable, OpenBSD is probably the most secure OS around.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the end, I’m probably going to stick with my Windows setup and get all my Linux development fix through MSYS2 until I realllly need a Linux dual-boot. I’ve allocated 150GB on my 1TB HD for another OS install and am leaving it blank for now. I’m also seeing if I can get Redox to build on my older Linux machine in the meantime. I’d like to try kernel development, but at the same time the deeper I look into it the more I realize just how out of my depth I am. Nothing to do but keep pressing forward and learning more, though.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Operating System Shopping (1/2)</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-15-operating-system-shopping-1-2.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-15-operating-system-shopping-1-2.html</guid><pubDate>Mon, 15 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I’ve been looking at operating systems to use on my Laptop. It has an Intel processor and NVIDIA graphics coprocessor, just like the majority of gaming laptops out there.&lt;/p&gt;
&lt;p&gt;The operating system it came installed with, and the one the most people are familiar with, is Windows. To be honest, Windows is a mess of an operating system. The kernel is full of hacks and workarounds to accommodate for legacy code, the whole registry concept is ginormous and unnavigable, and good luck trying to cleanly uninstall everything. History shows that Microsoft ensured their OS’s dominance through guerrila corporate tactics of allowing MS-DOS to be licensed for multiple hardware vendors, gaining followers in the business realm through those vendors and some killer apps, then forcing those same vendors to ship Windows when it released, furthering the cycle. Simply by virtue of being the most prominent OS early in the business realm, (not the first OS created, mind you), it became the self-perpetuating standard.&lt;/p&gt;
&lt;p&gt;Another operating system I’ve had a lot of experience with is Linux. My favorite distro used to be Lubuntu (Ubuntu shipped with LXDE), but while I was a Sysadmin that chnged to Arch Linux. Arch Linux is the bleeding-est edgeing-est distro out there, lagging maybe a week behind upstream releases at most. The maintainers put a lot of work into making sure everything works together even when it shouldn’t (Python 3.7 + CUDA 10 + Tensorflow 1.14 not even close to officially supported, at yet it worked (not flawlessly but it did do stuff most of the time)). I had Arch Linux dual-booting with Windows on my old laptop and enjoyed it a bunch.&lt;/p&gt;
&lt;p&gt;I’ll get into the reasons why I am OS shopping in the next post, as well as what I like and don’t like about the OSes.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Fighting off disease</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-13-fighting-off-disease.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-13-fighting-off-disease.html</guid><pubDate>Sat, 13 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Well shoot. I remember feeling exactly like this the last time I was vaccinated (1 month ago) but it always is a shock to feel just how bad it is. My shoulder is stiff, my joints ache, and overall I’m feeling super tired. (Man, just like an old man, huh?). I know I’ll come out the other side stronger and more disease-resistant, and wouldn’t even consider dropping vaccination, but still, why’s my body have to be so bad when fighting off disease?&lt;/p&gt;
&lt;p&gt;That’s an easy question: when your body does fight off disease, the best thing for it to do is convince you to do is to expend as little energy elsewhere as possible. That means aches and pains to prevent physical movement and exhaustion to prevent mental exertion. Really, quite logical. It also makes perfect sense that when fighting off a disease analog that, mind you, whose whole purpose is to trigger the immune system so your body will react in the exact same way. The higher order functions of the brain simply can’t do much about it.&lt;/p&gt;
&lt;p&gt;And here I am, lying in bed, rationalizing why I haven’t moved yet. Time to get up, I guess.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Morning vs Night</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-12-morning-vs-night.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-12-morning-vs-night.html</guid><pubDate>Fri, 12 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;American culture certainly seems to favor staying up late. I can’t count how many times my friends bragged about staying up until 2am to finish a project. I can count how many times I’ve heard of someone getting up at 4am to do something, though: one. My ultimate frisbee captain last year would apparently wake up early to do homework and lift weights, and it showed. He was ripped and getting all the good grades.&lt;/p&gt;
&lt;p&gt;Maybe that case can be attributed to night owls being more braggadocious than early birds, but still. There’s something about staying up late that’s easier for most people and looked on as the cool thing to do. Not me, unfortunately. At 10pm, right on schedule, it feels like my brain shuts down. Sometimes even before that. I go from moderately productive to a tired, forgetful, blathering mess. It’s partly a mental block but I really cannot stay up late very well. I would much prefer to get up early, where I can wake up more as I do more stuff. For me, at least, waking up at 7am vs 9am gives about the same level of exhaustion later in the day, only in the first case I have two more hours to do stuff.&lt;/p&gt;
&lt;p&gt;So, uh, the point is, I didn’t really enjoy writing these posts at 10:30pm every night so I will try to write them in the morning instead. We’ll see how it goes. Sorry for slacking off since the end of vacation; unlike art, I didn’t immediately pick this habit (or Duolingo D:) back up.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Vacation End Post</title><link>https://www.hazelduvall.dev/blog/posts/2019-07-06-vacation-end-post.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-07-06-vacation-end-post.html</guid><pubDate>Sat, 06 Jul 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Heyyy, I’m finally back from vacation! Yes, I had a great time, and yes, I saw lots of family and did the classic American things like play cards and eat barbecue and shoot fireworks and water slalom ski and yeah it was pretty awesome I’ll tell you what. I’ll elaborate more on some aspects later (little cousins + wakeboarding probably).&lt;/p&gt;
&lt;p&gt;Looking back at my older posts… yeah uh I was really not kidding about that art thing. I still am not kidding and want to practice again today even though I’ve sat 9 hours in the car and am feeling blergh. Don’t have too many deep thoughts right now since my brain is friend from a &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Legend_of_Korra&quot;&gt;Legend of Korra&lt;/a&gt; marathon in the car, so yeah I’ma just end this post here. See y’all bots tomorrow!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Vacation Start Post</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-27-vacation-start-post.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-27-vacation-start-post.html</guid><pubDate>Thu, 27 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So this will be my last post for a while. I’m going on vacation to Michigan with my family so I not get to use my phone before bed anymore. Really not much at all for that matter, because I will be prioritizing time with extended family instead.&lt;/p&gt;
&lt;p&gt;Going up to the lake in Michigan has been a family tradition for who knows how long, at least since Dad was a baby even. This year we’ll me making a bit of a detour first in New York to attend my maternal grandfather’s funeral, which is tough, no one is prepared to deal with that kind of emotion with the loss of a family member. It’ll be strange to be all mournful and then cheery as we drive to the lake the next day but I digress.&lt;/p&gt;
&lt;p&gt;Expect another post detailing my thoughts on my vacation after I get back. I hope the habits I worked so hard to build this summer, like Duolingo practice in the morning, Art practice in the evening, and blogging in the late evening aren’t disrupted by this week of other stuff. Anyways, see ya later!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 11</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-27-qotd-11.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-27-qotd-11.html</guid><pubDate>Thu, 27 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“YESSSSS!!”&lt;/p&gt;
&lt;p&gt;-Quinn, after magically guessing who Hitler was in the game Secret Hitler
(i went over to a friend’s house today, we had a blast with a bunch of card games. Skipped art but totally worth it to keep these friendships intact)&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>Streaming Art</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-26-streaming-art.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-26-streaming-art.html</guid><pubDate>Wed, 26 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Eh I missed a post again, whops.&lt;/p&gt;
&lt;p&gt;Anyways so yeah I’ve been streaming art the past couple of days very regularly. Most of the time I get my friend on in there, and we have a blast chatting, but for the past 2 nights in a row somehow I’ve had a new random dude jump in chat. I advertise my stream as a “chill stream” like 90% of the other streams on the platform, and somehow these guys chose me to converse with. I don’t know why; it can’t be the art quality, even those both seemed to be pleased with it; it can’t be my setup, the thumbnail isn’t amazing most of the time I don’t think. But I pride myself on audience interaction so I guess they stay around and even follow.&lt;/p&gt;
&lt;p&gt;All of this is very nice for one big reason: having someone to talk to while I do art is very motivating. It a habit now, if I don’t have someone looking on then it just becomes boring. When I’m reading chat I can let my mind wander to other things besides how bad I think my art is (pretty bad, which it isn’t compared to professionals although pretty good compared to where I started out (I’m not done improving yet, though, my goal is to be able to quickly draw relatively high quality fan art like the more popular artists I see)). That puts me in a state of flow, or zen, or whatever you want to call it where your mind is able to focus on the task at hand without even considering outside distractions. Checking chat is just part of that flow for me now I guess. Cool.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 10</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-26-qotd-10.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-26-qotd-10.html</guid><pubDate>Wed, 26 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;—FAQ THREAD ABOUT THE NEW #Discord VIRUS—&lt;/p&gt;
&lt;p&gt;-Well meaning twitter user @splitsplatted
(It was more of a phishing attack than a virus, but the whole this is pretty interesting. Link &lt;a href=&quot;https://twitter.com/splitsplatted/status/1143556723266994176?s=19&quot;&gt;here&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>I read a book today</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-24-i-read-a-book-today.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-24-i-read-a-book-today.html</guid><pubDate>Mon, 24 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I read a book today. Started reading, to be precise. I should read more often; it was very enjoyable. First, though, I should probably find more active things to do so I’m not feeling bored and lethargic enough to start reading randomly. Or maybe that’s a bad way to think: reading is actually really good apparently, crucial even to a well-balanced life. So maybe I’ll do it more often now. Cool.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>On Learning</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-23-on-learning.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-23-on-learning.html</guid><pubDate>Sun, 23 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;(This is that essay I talked about. Copy-pasted in its entirety.)&lt;/p&gt;
&lt;p&gt;As I transition from high school to college, I’ve done some thinking about how I best learn. After all, so I’m told, college is where students are challenged to pace themselves, the bulk of the work being done outside the classroom. This in and of itself doesn’t bother me; I can time-manage and slog through mountains of homework with the best of em. No, what bothered me is this: if I don’t know my own strengths, then I can’t play to them to save time or shore up my own weaknesses.&lt;/p&gt;
&lt;p&gt;After some experimentation, I could conclusively point out things that are not my strengths. I’m impatient; I’m set in my ways; I can’t focus on future plans; I have limited people skills; I underestimate the value of others; I can’t think fast, or strategically; I can’t visualize shapes clearly; I don’t have an ear for music. I was told I think too poorly of myself, that I can improve on any of these things with time, that professionals have dedicated years of their life towards learning something I can’t possibly hope to understand in one week. I had a hard time swallowing this. It seemed like shifting the blame, which is pretty shifty if you ask me.&lt;/p&gt;
&lt;p&gt;As an example, the other day, I tried to play the piano. &lt;em&gt;It’s just notes on a page, those are easy to read&lt;/em&gt;, I thought. Individually, yes, after a good ten seconds of counting up or down from middle C. Then came the unanticipated challenge of getting my fingers to press the right notes without looking. Then came stringing all that together at a reasonable pace. I pressed through for a bit longer, learning to play a few bars, but then I got discouraged by lack of immediate progress. It was just another frustrating riff on other unfamiliar subjects I’d tried before, like art, Tetris, and basketball.&lt;/p&gt;
&lt;p&gt;So, what was I comfortable with, able to do quickly and without a second thought? Programming comes to mind. What’s so special that makes me suited for it? Broad information synthesis? A keen eye for details? A knack for language of any sort? Raw experience curated by years of specialization? If it’s the last of the bunch, I feel cheated. I want to get good at a lot of things, and yet the only path towards that goal is time? What a ripoff. Time is precious. It doesn’t seem physically possible, let alone desirable, to spend every waking hour working towards one goal after another.&lt;/p&gt;
&lt;p&gt;As I thought these things, I confided in a friend. He told me this: your perspective is totally off. First, you need to stop comparing yourself to others; it’s unhealthy. Then, you need to slap yourself in the face, tell yourself you &lt;em&gt;are&lt;/em&gt; good enough, and stick to whatever constructive practice regimen is necessary. You will get better. You might not ever reach your goal, but you will get better, which is what matters. I was shook, for lack of a better word. Logically speaking, it makes sense that good artists, musicians, public speakers, and sports players spend years perfecting their craft, years which I don’t have under my belt. And yet some notion possessed me to think I could get the same results, only better and more quickly, simply because I could understand &lt;em&gt;what&lt;/em&gt; they were doing, not ever really &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Being relieved of that thought train was sobering. It did nothing to lessen the frustration I felt when I couldn’t draw a precise curved line, couldn’t beat my friend at Tetris, or couldn’t put that darn large orange ball in the darn red hoop. Instead of submitting, though, I now know what to do: keep going. I’m still at a loss for how to play to my strengths. But by some miracle of hard work I made it through high school, and gosh darn it, I’ll work my butt off to keep improving through college and life as well. In my opinion, that’s what being human is all about.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 9</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-22-qotd-9.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-22-qotd-9.html</guid><pubDate>Sat, 22 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“I have another friend who’s also learning Japanese, and they already know all the Katakana and that bugs me.”&lt;/p&gt;
&lt;p&gt;-My friend who is concurrently doing Japanese Duolingo with me
(he’s a really nice dude, great friend, always watches  my art stream when I invite him. We do lots of stuff together, expect more quotes)&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>Am I smart?</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-22-am-i-smart.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-22-am-i-smart.html</guid><pubDate>Sat, 22 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Signs seem to point to yes. No bragging, but I did get As in every class except B+ freshman Spanish, even in classes most people did poorly in. But there’s a predicament: I don’t feel smart most of the time. Maybe it’s me or maybe it’s a human problem, but I can’t really fully comprehend learning things any faster or slower than I already do. And maybe because I’m impatient, I feel like I learn things too slowly, leading me to believe I’m not smart.&lt;/p&gt;
&lt;p&gt;And maybe that’s true, too. That I am not smart. That especially seems to be the case when I compare myself to some classmates who knew more science, had better insights in humanities, and could comprehend higher math. I don’t study very often, but when I do it’s the most intense, “memorize this or die” feeling ever. I can’t tell if my memory is awful (I’ll easily forget deadlines that are more than 2 weeks out) or fantastic (what are the main quirks that differentiate Python 2 and 3? Easy, the print statement is now a function instead of a keyword, range has been replaced by it’s faster brother xrange, float division is now on by default, etc.). Or maybe just extremely specialized for handling certain facts and concepts (math?) but not others (vocabulary, except weirdly enough most SAT vocab words).&lt;/p&gt;
&lt;p&gt;Anyways the point I was trying to make but forgot to lead up to is that maybe the differentiator isn’t intelligence, but experience. And that scares me. Because right now, I may have the experience lead over some people, but everyone will catch up given time. So I don’t want to get caught on my butt, and I need to keep working to improve myself in the areas I most care about. Yeah.&lt;/p&gt;
&lt;p&gt;I have an essay I wrote a while ago for school about something similar, I’ll post that tomorrow b/c I can’t keep doing this staying up late thing, I wake up too late gosh darn it.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Why short post?</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-21-why-short-post.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-21-why-short-post.html</guid><pubDate>Fri, 21 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Short post today because I stayed up too late programming. It was very fun but took longer than I thought to make a python script that fetched the currently playing song from Spotify. Also bummed there weren’t any working existing solutions. So yeah at least now I have something going, and ready to be used on my next art stream. I should’ve actually practiced art today tho. Oh well.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 8</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-20-qotd-8.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-20-qotd-8.html</guid><pubDate>Thu, 20 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“Sour Skittles are actually legit, really sour unlike most things that have the more sugary sour crystals.”&lt;/p&gt;
&lt;p&gt;-My brother, over some not-really-sour pool ice cream
(We have very similar tastes when it comes to food, except I can handle more bitterness (vinegar, dark chocolate) and spice (wasabi, jalapeños).&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>Born</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-20-born.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-20-born.html</guid><pubDate>Thu, 20 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There’s a pretty philosophical question that’s been on my mind for a while: are people naturally born good or evil? The obvious noncommittal answer is that it varies, and the end result is also dependent on the state of society upbringing and such too. Then my next question is this: What, then, would be the natural tendency for someone in my same place to be, good or evil? Taking my parents and siblings into account, it seems the answer is good.&lt;/p&gt;
&lt;p&gt;But backing up a bit, there still seems to be an unanswered question here: what exactly makes a person good or evil? There are two parts to the English ambiguity of “make”: the first is definitions, and the second is causes. For the purposes of this thought train, I’d like to define “good” as always doing things for the benefit of others, and “evil” as always doing things for the benefit of self. I realize this might be slightly different from a tradition definition of good and evil as moral vs anti-moral but maybe I’ve shifted the morals around a bit, no?&lt;/p&gt;
&lt;p&gt;So the causes of good and evil: unclear. Genetics of the brain and upbringing
must have something to do with it (wow so deep that’s literally everything it
could be). I have no idea why some people seem to be inclined to help others,
and others only themselves. Maybe it even depends per-situation? See that’s why
I’ve been thinking about this. I want to be good. But I end up falling into my
own definition of evil (see &lt;a href=&quot;./2019-06-17-being-selfish.html&quot;&gt;Being selfish&lt;/a&gt;).
Yes other people want to be my definition of evil, and truly believe that is
the best thing. I understand it, I think I do, but I don’t know. (As a
side note, a lot of times conflicts can even arise between good and good people
depending on who they want to help).&lt;/p&gt;
&lt;p&gt;So there you have it. Some of  thoughts on naturally tendency and good and evil.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>What I want posts to be</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-19-what-i-want-posts-to-be.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-19-what-i-want-posts-to-be.html</guid><pubDate>Wed, 19 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I let the morning slip away again, only this time because I slept in. Felt really good actually. I shouldn’t be staying up this late because I want to get up early but yeah not having an alarm for once was nice (my phone died).&lt;/p&gt;
&lt;p&gt;Wait a minute this isn’t right. I don’t want these posts to be just a collection of diary entries. I want them to be deeper thoughts than that. While keeping a daily journal is nice, it’s be nicer to have a record of personal philosophy and stuff. The minutae can wait. Not even I will want to read that probably.&lt;/p&gt;
&lt;p&gt;So, I apologize for the decline in quality, and will get some better stuff going soon. In the meantime, more sleep. No quote today.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Scanning cards</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-18-scanning-cards.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-18-scanning-cards.html</guid><pubDate>Tue, 18 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My morning got off to a rough start. I was very lazy and wasted a lot of time on my computer instead of doing anything productive. I’ll try and remember how this feels and do better tomorrow.&lt;/p&gt;
&lt;p&gt;Part of the reason why I couldn’t focus was I was having friends over. Around 4:30 my favorite ground came over to help digitize our common card collection. Called &lt;a href=&quot;https://en.m.wikipedia.org/wiki/1000_Blank_White_Cards&quot;&gt;1KBWC&lt;/a&gt;, it’s a really fun game we’ve had going since Junior year of HS. We recently hit the thousand card milestone recently with the help of the rest of our club members (we were the founders). Anyways yeah we had this whole setup going, digital scanner going, green screen for pencil cards that didn’t scan well, sorting by who made the card, the whole shebang. We plan to host a MediaWiki server with all cards in picture form along with tags for who made them and maybe categories of cards. We also did other things, like eat pizza and play Puyo Puyo Tetris (that’s another post), but the gathering was focused around card digitization. Which was good because we’d been talking about it for a while and needed an excuse both to get together again and to accomplish that task.&lt;/p&gt;
&lt;p&gt;All in all, another fantastic summer day, non-ruined by rain.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 7</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-18-qotd-7.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-18-qotd-7.html</guid><pubDate>Tue, 18 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“Hey guys, did you know that ‘portmanteau’ is a portmanteau of ‘portmanteau’ and ‘portmanteau?’”&lt;/p&gt;
&lt;p&gt;-Noah, over pizza
(he’s a funny dude. Also really good a Tetris)&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>QOTD: 6</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-17-qotd-6.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-17-qotd-6.html</guid><pubDate>Mon, 17 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“Let’s call it…Operation Studfinder! &lt;em&gt;points finger at me and beeps&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;-Dad, while getting tools to mount a TV on the wall
(thank you Dad. Btw we didn’t finish mounting that TV yet)&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>Being selfish</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-17-being-selfish.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-17-being-selfish.html</guid><pubDate>Mon, 17 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I am way too selfish. Nearly every thought I have centers around me. Only with a fair amount of effort can I logically think through what others would want and then act accordingly. I don’t like this. Right now, it just caught myself again: my first thought as to why I don’t like this was, “it makes me feel self-conscious and like a lesser human being,” but the non-selfish response should’ve been, “I’m not able to do enough for others because I only think of my own interests.” Both are true statements, but one shows better character than the other.&lt;/p&gt;
&lt;p&gt;I love talking about myself and the things I like, and will never pass up a chance to flaunt some new or obscure knowledge I have. I worry that can be isolating, like, “ooh look at mr. smarty-pants over there flexing again.” Am I over-thinking it? Should I watch myself more? Maybe to both. I care too much about how I come across, because again, I’m selfish.&lt;/p&gt;
&lt;p&gt;I won’t pretend like being aware of my own faults is making me a better person. Even correcting for my mistakes isn’t enough. But I’m scared. Because I don’t know how to change. My hesitation around strangers, my habit of blurting facts, my selfishness, all seem ingrained. And I don’t know who to talk to, because all the people I trust the most I want to think highly of me so they trust me back. So I probably won’t reveal my deepest insecurities, because I’m selfish. Which isn’t ok. So I’m typing them here, for potentially everyone to see. Which is ok. Maybe I’ll change eventually and come back and wonder what I was so worried about. I don’t know. It’s too late for this and my plan of just writing out thoughts has worked because I have these thoughts every night but don’t share them. Anyways gn.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 5</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-16-qotd-5.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-16-qotd-5.html</guid><pubDate>Sun, 16 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“Mom’s happy and she doesn’t even know it: I was &lt;em&gt;this&lt;/em&gt; close to buying a new 4K TV we didn’t need, but none of them were the right size…”&lt;/p&gt;
&lt;p&gt;-My Dad at Best Buy
(he’s a rascal sometimes :P)&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>Father&apos;s Day</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-16-fathers-day.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-16-fathers-day.html</guid><pubDate>Sun, 16 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My dad is pretty awesome, not gonna lie. He works hard, imparts good life advice, is always patient with us rambunctious kids, and just is a great person. I hope my family was able to provide a good enough father’s day to keep up with his awesomeness. Me and my brother helped with fixing the TV sound setup downstairs and cleaning the old junk, we had lunch together while out shopping for electronics supplies, we watched the original “Mission Impossible” after we were done, and then we went to his favorite Indian restaurant for dinner. Then ice cream afterwards.&lt;/p&gt;
&lt;p&gt;All around, a pretty productive and fun day spent entirely together. He seemed happy, but also kind of sad at times. Was he realizing that this summer will most likely be the last spent like this? Did he wish he could be doing other things but was too polite to say it? I don’t know. The first is definitely what’s sad about this summer to me, and the second is definitely within his nature. In any case, I should probably help finish mounting the TV tomorrow (we bought a new mount for the downstairs one). He deserves this kind of attention every day, as does every kind and loving father.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Today&apos;s Results</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-15-todays-results.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-15-todays-results.html</guid><pubDate>Sat, 15 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;What I did today, in bullet point form:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Woke up late&lt;/li&gt;
&lt;li&gt;Made oatmeal&lt;/li&gt;
&lt;li&gt;Watched YouTube while eating said oatmeal&lt;/li&gt;
&lt;li&gt;Played video games&lt;/li&gt;
&lt;li&gt;Went over to a friend’s house for their graduation party. It was very fun, got to see old friends and make new ones. All in all a great experience with lots of physical activity, card games, and the staple of any teenage party: video games. Lunch and dinner were had there, tacos.&lt;/li&gt;
&lt;li&gt;Did some art. Worked way too long on it for something I’m not terribly proud of but hey I practiced.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Result: I wish I could’ve gotten up earlier but that was another great summer day. Won’t have too many of these left nope. Gotta get together with friends soon.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 4</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-15-qotd-4.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-15-qotd-4.html</guid><pubDate>Sat, 15 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“Yet in view of wider adoption of Mixed Reality (MR) technologies, surprisingly little attention has been given to the critical nature of the privacy and security implications of MR.”&lt;/p&gt;
&lt;p&gt;-Microsoft, &lt;a href=&quot;https://www.microsoft.com/en-us/research/blog/envisioning-privacy-preserving-image-based-localization-for-augmented-reality/&quot;&gt;https://www.microsoft.com/en-us/research/blog/envisioning-privacy-preserving-image-based-localization-for-augmented-reality/&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
(that was actually a pretty good read, even if it boils down to, “turns out neural networks can extrapolate useful information from feature-labeled 3D point clouds, so we turned the point clouds into line clouds and now they can’t. Fancy visuals!”)&lt;p&gt;&lt;/p&gt;
</content:encoded><category>quote of the day</category></item><item><title>QOTD: 3</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-14-qotd-3.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-14-qotd-3.html</guid><pubDate>Fri, 14 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“I misread ‘volt padmount’ and thought it said ‘Voldemort’ instead”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The person who started the “Voldemort Transformer Moment” meme
(some discord servers I’m in are purely to view their stupid funny memes)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>Another story about trying</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-14-another-story-about-trying.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-14-another-story-about-trying.html</guid><pubDate>Fri, 14 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hey I felt better today. Had a wacko dream but hey no more constant weakness. I even biked over to gamestop to pick up an Xbox controller, that was fun. Anyways yeah cool day, weather was perfect, spent some time outside with the dogs in the cool summer breeze, at the pool eating $3.50 hamburgers with my sister, and inside cleaning my desk. The desk is still cluttered but much less so. The pencil holder 3D thingy (yes that’s what that was) coming in clutch.&lt;/p&gt;
&lt;p&gt;Art Hour (9:00-10:00 most nights) was disrupted by my sister’s dance recital (she was awesome, wouldn’t have missed it), but I thought I would make up for it my transcribing a few notes from one of my favorite songs in the 15 minutes I had remaining. Turns out no, my musical ability is super rusty. Even at my (still quite low) prime, I probably wouldn’t have made more progress. That is, to say, zero. I started out with the background chords, realized I don’t know any chords except for the standard major/minor 5th (where you press the 1,3,5 keys, is that right?), which these complicated ones were not. I then moved on to trying to decipher the melody. It should’ve been easy, there appeared to be only 3 notes, all within 1 whole step of each other, but even finding the “base” note was beyond me. In conclusion, I was woefully underprepared. Guess I’ll take another shot at it tomorrow and/or ask my friend for help.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 2</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-13-qotd-2.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-13-qotd-2.html</guid><pubDate>Thu, 13 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“See you later, Hazel.”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mr. White, Syslab Director TJHSST
(I might cry, thinking about leaving TJ is too emotional for me rn)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>A good day</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-13-a-good-day.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-13-a-good-day.html</guid><pubDate>Thu, 13 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;With everything extremely sore, and feeling quite weak from the large immune response the vaccine yesterday prompted, today was not set to be a good day. But it was anyways, I’ll tell you why.&lt;/p&gt;
&lt;p&gt;Today was the last day I set foot in my high school for a long while probably. I handed out thank-you notes to my favorite teachers, got to talk for an hour with my favorite-est teacher, and generally re-feel that nostalgic feeling of loving something but knowingly you are lettting it go but promising to never forget all the good times.&lt;/p&gt;
&lt;p&gt;I also got to experience that mystical feeling of “flow” you get when you lose all track of time doing something you really love. For me today it was programming and art. Both sedantary activities, yes, but with my body screaming “no” to simply existing I didn’t want to risk it. When it got really bad (around noon) I just loaded up a few glasses of water and binge-watched 4 episodes of RWBY volume 6. Good show. Later, after programming but before art, I made dinner with my mom and sister. That was fun.&lt;/p&gt;
&lt;p&gt;Anyways yeah it turns out mild physical discomfort can be mitigated by doing fun stuff. yey.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Something about Doctors idk</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-12-something-about-doctors-idk.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-12-something-about-doctors-idk.html</guid><pubDate>Wed, 12 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Got caught up on my Meninngococcal vaccines today. The bruises still hurt, as per usual, but I think in another 48hr I’ll be completely fine. The lady doing them was still in training but she was very nice. She talked about how she, at one point, worked full-time (60hr week!) &lt;em&gt;while also&lt;/em&gt; going to community college full time, only quitting when work made her move 2hrs away from college! She said at that point she had already given up on sleep but the extra commute made it impossible. That’s hardcore, and again reinforces how lucky I am and how easy I have it. She’s now working for the medical center and taking online classes over the weekend to finish off her degree.&lt;/p&gt;
&lt;p&gt;Oh yeah now I remember why I wanted to talk about doctors. The replacement one I had was a real kook, no better way to describe him. He seemed to be around 70, had a killer white mustache and beard, and constantly cracked pretty bad dad-jokes (I could keep up with his torrent, even firing a few back). He certainly knew what he was doing though, and fortunately the checkup went flawlessly. Turns out I am a healthy boiyo with no health problemos. yey. Let’s keep it that way.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>QOTD: 1</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-12-qotd-1.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-12-qotd-1.html</guid><pubDate>Wed, 12 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Tell your parents your doctor introduced you to sex, drugs, and rock-and-roll, hah!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The doctor I had today
(trying out a new thing at the suggestion of my friend. Basically posting a memorable quote from each day in addition to the usual post)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;</content:encoded><category>quote of the day</category></item><item><title>Sleep</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-11-sleep.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-11-sleep.html</guid><pubDate>Tue, 11 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m not entirely sure how I keep forgetting to post. I wasn’t that tired when I fell asleep. Or so I thought, before I ended up snoozing for 11 hours straight. I guess that means I maybe caught up on the sleep I missed during the ANGP on Saturday. Maybe not, thought, and now I’m used to just used to waking up late. Hmm.&lt;/p&gt;
&lt;p&gt;Idk if I’ve mentioned this in a previous post, but I, like most humans, absolutely adore sleeping. I’m reminded of one meme where someone says, “You’ll spend about 1/3rd of your like unconscious, unable to do anything except think about things you have no control of. And the best part is, that’ll be your favorite part.”&lt;/p&gt;
&lt;p&gt;That’s a bit of an exaggeration, but still, you’d think sleep would be useless. My classmates most certainly do. One of my particularly sleep-deprived friends measures his “sleep deficit” from 6:20hrs a night. And his chart still went into the red. Personally, I’ve found sleep to be like a secret weapon for learning things fast, better than staying up to study in fact. Not that you shouldn’t study at all, you most certainly should, but like after a certain point you’ve reviewed all that you can and sleeping on it and being well rested for the test the next day is the better option.&lt;/p&gt;
&lt;p&gt;Anyways. I hope I’m both able to break my current summer habit of late to bed and rise and shift it to early, as well as keep that up in college. We’ll see.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Elementary School Reunion</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-11-elementary-school-reunion.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-11-elementary-school-reunion.html</guid><pubDate>Tue, 11 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Yup you read that right. My elementary school had a reunion party tonight to celebrate our current graduation from high school. And I went to it.&lt;/p&gt;
&lt;p&gt;It was actually pretty fun. I had one friend, son of a family friend, who I had kept in touch with, but that was pretty much it. The rest I had never reached out to again (it was 5th grade in 2012, idt we had phones yet), let alone remembered. I was probably the worst there are remembering names and faces, so I’m grateful to my friend for busting out the old 5th grade yearbook and giving me a tour.&lt;/p&gt;
&lt;p&gt;Most of them went to the same or a nearby high school, while I had moved in for
just 5th grade and moved out the year after. I was an antisocial little kid,
only making a few friend and sticking to them. Still am, come to think of it. I
emphasize the point of having &lt;a href=&quot;./2019-06-06-friends.html&quot;&gt;Friends&lt;/a&gt;, but in
reality my mind just goes blank when I talk to strangers. I can think of
anything to talk about, don’t know how they’ll react to what I say at all if I
do say something random, and yeah. A couple people were nice enough to make
conversation, girls even, and I got to meet up with an old friend who I’ll keep
in touch with now again, so I won’t consider the night a complete waste. Plus
the free Mexican was nice.&lt;/p&gt;
&lt;p&gt;Anyways yeah if this is the first post you read, uh, I’m sorry, but a lot of the rest of the blog is like this. Check out the projects section if you want something a bit more professional.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>ANGP</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-09-angp.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-09-angp.html</guid><pubDate>Sun, 09 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I just set foot in TJHSST for the last time in probably a long while. The All Night Graduation Party was held there, and I went, despite not staying up all night. (That’s also why I missed yesterday’s post). I had a great time, but my friend William had a good observation: despite all the wild revelry we had been having, everything was tinged by remorse and nostalgia and wandering thoughts about what had been.&lt;/p&gt;
&lt;p&gt;I would’ve liked another “last time,” and will probably count the final time I stepped foot in the Electronics Lab and talked to Mr. Bell as my final moment in TJHSST. Gosh darn was that also sad, me and Alexander had to fight back choked throats and blink away the starts of tears as we left the wonderful room filled to the brim with any imaginable breadboard component, where so many memories of true freedom reigned, the place anyone could unequivocally point to and say, “this opportunity is what’s so special about TJHSST.” Reliving the experience is hard.&lt;/p&gt;
&lt;p&gt;HOLY COW I ACTUALLY TOOK A PICTURE OF THE 3D THINGY FINALLY here it is:&lt;/p&gt;
&lt;img src=&quot;https://www.hazelduvall.dev/static/IMG_4038-Copy.jpg&quot; alt=&quot;the 3d thing&quot; width=&quot;300&quot; height=&quot;225&quot; /&gt;</content:encoded><category>daily thoughts</category></item><item><title>Friends!</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-06-friends.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-06-friends.html</guid><pubDate>Thu, 06 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I highly recommend having some. I pretty miserable at putting myself out there to meet new friends, but once I find people with common interests and compatible personalities, I think we can hit it off fast. Maybe that’s my imagination, but the making a lot of friends part isn’t. Throughout nearly all of high school, I’ve had one cadre of 4 other really close friends. Today, we all met together at one of the group’s house for a small school-is-done party, complete with live-streaming sandwich making, playing Frisbee, Minecraft, and Monopoly. Really fun!&lt;/p&gt;
&lt;p&gt;Friendships, like anything else, I think, take time. It takes time to learn how to make friends, and it takes investment of time to keep friends. Unfortunately I’ve slacked off on the first (already having good friends) and haven’t put as much time into side-friendships as I should have (again, due to a group of already amazing friends). My general strategy going into college is this: keep in touch with all of my best friends and some other good friends, join a lot of clubs and activities, and just meet as many people as I can under circumstances where we can just do stuff together with no pressure to be friends and hopefully by virtue of just time spent together talking about stuff something will develop. Very hazy, I know, but what can I do? Spend the summer trying to make friends with people that I won’t be seeing ever again? I don’t know how best to make friends yet (although I’ve gotten a lot of good advice), so we’ll see what happens. Later.&lt;/p&gt;
&lt;p&gt;Ah yes here’s the paragraph where I talk about the 3D thing you aren’t quite sure exists anymore due to how long I’ve been putting off showing a picture of it. Well I spent so long at the party today I didn’t have time to take a picture when I got home. AND I forgot to do that in the morning rush. So there. I promise it’s really cool, maybe not worth this much wait but still cool nonetheless. See ya tomorrow.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>A true eclectic collection of thoughts</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-05-a-true-eclectic-collection-of-thoughts.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-05-a-true-eclectic-collection-of-thoughts.html</guid><pubDate>Wed, 05 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The game: only reveal my thoughts online, and nothing physical. If close friends find out about this blog they will know me even better because I usually don’t share what I think.&lt;/p&gt;
&lt;p&gt;Yay I was able to practice art today, along with everything else (including programming!), but at the cost of sleep. Thank you, friend who did art with me.&lt;/p&gt;
&lt;p&gt;Wait a minute I have to get up early tomorrow. How am I going to fit it my morning &lt;a href=&quot;https://duolingo.com&quot;&gt;Duolingo&lt;/a&gt; practice? Going to friend’s house in the afternoon, might be too late. We’ll see.&lt;/p&gt;
&lt;p&gt;Oh yes the 3D printed thing. Good news: it finished! Bad news: I forgot to take a picture. Tomorrow!&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Forgot to practice</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-04-forgot-to-practice.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-04-forgot-to-practice.html</guid><pubDate>Tue, 04 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Stuff I did get around to after school today:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Walking my dogs&lt;/li&gt;
&lt;li&gt;Making dinner&lt;/li&gt;
&lt;li&gt;Cleaning the kitchen&lt;/li&gt;
&lt;li&gt;Exercise&lt;/li&gt;
&lt;li&gt;College finances (a little bit, but it helps)&lt;/li&gt;
&lt;li&gt;Color coding my &lt;a href=&quot;https://www.thunderbird.net/en-US/&quot;&gt;Thunderbird&lt;/a&gt; calendars&lt;/li&gt;
&lt;li&gt;Watching art videos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stuff I did not get around to after school:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Practicing Super Smash Bros. (did a lot of that during school, shouldn’t matter)&lt;/li&gt;
&lt;li&gt;Practicing what I learned in the art videos&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I should be better about this…but I don’t want to sacrifice sleep. This post is usually the last thing I do before I go to bed (I know I know, unnatural light is bad, too bad).&lt;/p&gt;
&lt;p&gt;Also, update on 3D print thing: what was supposed to be a 15hr print turned into a 30hr one (I knew I should’ve turned off infill), so it’s still going. I promise tomorrow.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Art Again</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-03-art-again.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-03-art-again.html</guid><pubDate>Mon, 03 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Haha yes &lt;a href=&quot;https://www.clipstudio.net/en&quot;&gt;Clip Studio Paint&lt;/a&gt; is truly a magical piece of Japanese software. All the brush and texture presets are very quality and emulate a lot of the classic manga stuff you see a lot.&lt;/p&gt;
&lt;p&gt;Coming from &lt;a href=&quot;https://krita.org/en/&quot;&gt;Krita&lt;/a&gt;, there’s a palpable increase in professionality and polishedness of the whole system, even if the UI style isn’t exactly modern. I still need to get used to the key bonds but fortunately a lot carries over.&lt;/p&gt;
&lt;p&gt;I know using a new art program won’t automatically improve my drawing skills, but at least now I don’t think I’ll have to try as hard to get certain things done. Plus I like the presets more. Too bad it’s paid, but I’m definitely willing to shell out a cool $50 for a professional program with (hopefully) lifetime updates.&lt;/p&gt;
&lt;p&gt;Also, about the 3D thing I said I was going to show? Yeah uh the filament broke in the middle of the night around 1/3rd the way through the build, had to restart :(. Tomorrow then.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>You FOOL</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-02-you-fool.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-02-you-fool.html</guid><pubDate>Sun, 02 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You thought I was done with these daily blog updates? HA, think again! I have so much more to complain about to no one in particular but am uncomfortable saying aloud because I have self-esteem issues and think my friends will think less of me if I bother them with inane problems!&lt;/p&gt;
&lt;p&gt;Anyways, why the heck does it take so long to 3D print stuff? &lt;a href=&quot;https://www.lulzbot.com/cura&quot;&gt;Cura&lt;/a&gt; says it’ll take 20 hours for this cool-looking pencil holder thing to get made. I don’t know if I can wait that long, but I already started the build, so we’ll see. Maybe tomorrow there’ll be a photo?&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Senior Research</title><link>https://www.hazelduvall.dev/blog/posts/2019-06-02-senior-research.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-06-02-senior-research.html</guid><pubDate>Sun, 02 Jun 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I don’t know if anyone else will read this paper, but here it is:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.hazelduvall.dev/static/final_paper.pdf&quot;&gt;RLAIT.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I spent a whole year on this. I learned a lot, but unfortunately don’t have a whole lot to show for it. Still cool and very fun and I would do it again.&lt;/p&gt;
&lt;p&gt;Code: &lt;a href=&quot;https://github.com/hazelduvall/RLAIT&quot;&gt;https://github.com/hazelduvall/RLAIT&lt;/a&gt;&lt;/p&gt;</content:encoded><category>projects</category><category>AI</category><category>TJHSST</category></item><item><title>Whops: the unnumbered</title><link>https://www.hazelduvall.dev/blog/posts/2019-05-30-whops-the-unnumbered.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-05-30-whops-the-unnumbered.html</guid><pubDate>Thu, 30 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;No, I haven’t been asleep since I last posted. I just forgot to post. Again. Yes I’m bad, thanks for asking. Making habits is hard.&lt;/p&gt;
&lt;p&gt;Anyway, today’s topic: DRM. It sucks. I realized I’ve been trying to break it in a completely selfish way, but still, c’mon, please just yield to my halfhearted googling attempts already. I think I’ve got the full file (probably not, it was something stupid like removing the “Range” header on a request whose only authentication was in a temporary token and hmac included in the URL), but there’s a bunch of audio decoding errors after the first 10 seconds. Another stupid python script to get all the individual bits failed spectacularly (I think there was an extra bit returned by the server that complicated things? idk).&lt;/p&gt;
&lt;p&gt;So yeah when people talk about how unhackable stuff like WideVine is, they really mean it. I was probably too lazy to even get to the part where encryption is a problem! Anyways yeah today I again learned just how much I don’t know.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Being tired</title><link>https://www.hazelduvall.dev/blog/posts/2019-05-26-being-tired.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-05-26-being-tired.html</guid><pubDate>Sun, 26 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Oh boy am I tired right now. I can’t remember the last time I was this exhausted; it was probably during wrestling season sometime. I might have heat stroke, I don’t really know&lt;/p&gt;
&lt;p&gt;The thing is, my “normal” tired is the tired you’d feel after you first wake up, that thing where you kind of want to go to sleep but your brain (if it’s unaddled enough) tells you that a little bit of movement will shake it off. I feel that in school all the time, sluggish a little bit but overall once engaged in something I’ll feel awake.&lt;/p&gt;
&lt;p&gt;Not now. Now I have a fever, all my limbs are heavy, thinking is hard, I have the classic dehydration headache (as opposed to my other “screw you alergies” migrate), and overall just bleh. The weird part is I don’t have an appetite; I had to force myself to eat enough lunch and dinner. Physical activity seemed like it would make my body implode even more than it currently is, so I avoided it. I definitely spent too much time outside in the sun (it shows in my terrible-looking farmer’s tan too).&lt;/p&gt;
&lt;p&gt;Anyway, game results: we only won our very last game in the tournament, clutching that sweet sweet 11th/12 place. Maybe I’ll talk about Wilson, the team that crushed us and probably won the entire thing, tomorrow.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Whops pt. 2: Boogaloo</title><link>https://www.hazelduvall.dev/blog/posts/2019-05-25-whops-pt-2-boogaloo.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-05-25-whops-pt-2-boogaloo.html</guid><pubDate>Sat, 25 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Forgot again yesterday. Uhhh something about how short-hops in Suepr Smash Bros are hard to do in the heat of the moment.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Frisbee</title><link>https://www.hazelduvall.dev/blog/posts/2019-05-25-frisbee.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-05-25-frisbee.html</guid><pubDate>Sat, 25 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I went to an Ultimate Frisbee tournament today. Played in, specifically. For those unfamiliar with the game, Ultimate Frisbee is a non-contact sport played with the classic Frisbee where teams of 7 players attempt to catch the Frisbee in the opponent’s end zone while blocking the opponent from doing the same to them.&lt;/p&gt;
&lt;p&gt;It’s a good sport, and I had a lot of fun today even though now I’m exhausted. I like Frisbee because it’s something active to do with friends. Really any sport could be like that but the culture around UF is very welcoming compared to other, more competitive sports.&lt;/p&gt;
&lt;p&gt;I guess tomorrow’s post will be about how we did in the tournament, we play 3 more games tomorrow too to determine our final placing.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Calendars</title><link>https://www.hazelduvall.dev/blog/posts/2019-05-23-calendars.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-05-23-calendars.html</guid><pubDate>Thu, 23 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I don’t know why, but I haven’t gotten into any habit of using them. I know they’re useful, but I don’t check or put any dates on them.&lt;/p&gt;
&lt;p&gt;Come to think of it, that’s probably a self-perpetuating cycle. Huh.&lt;/p&gt;
&lt;p&gt;I’m usually fine with keeping all the important dates in my head. That’s worked out fine for quizzes and tests. Not so much for Senior Shirt Day (which was today) or other long-term planning things like internships. The former example is why I bring this up; missing the group photo, while kind of just novelty, sort of stings.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Putting things on the Internet</title><link>https://www.hazelduvall.dev/blog/posts/2019-05-22-putting-things-on-the-internet.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-05-22-putting-things-on-the-internet.html</guid><pubDate>Wed, 22 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I try to avoid it, mostly. I’m pretty sure only 3-4 photos of me exist publicly online. I’ve also tried to separate my “professional” accounts from my “personal” accounts, although with enough digging (no I’m not going to tell you where) it’s possible to link the two realms.&lt;/p&gt;
&lt;p&gt;This blog is actually on the “professional” side. Kind of strange to think about, I don’t do this kind of random thoughts thing anywhere else, even in private chat servers (except occasionally in DMs to friends). It’s kind of a load off to be able to just say stuff, even if it is to the loneliness of a self-hosted blog on the public internet.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Whops</title><link>https://www.hazelduvall.dev/blog/posts/2019-05-21-whops.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-05-21-whops.html</guid><pubDate>Tue, 21 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I can’t believe I forgot to post yesterday.&lt;/p&gt;
&lt;p&gt;Anyways, here’s yesterday’s thought: getting good at things takes time. So that’s why I try to do a lot of things every day. To get good at them all.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>Art stuff</title><link>https://www.hazelduvall.dev/blog/posts/2019-05-21-art-stuff.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-05-21-art-stuff.html</guid><pubDate>Tue, 21 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So I like doing art. I’m not great at it, but apparently practice has elevated me to above-average now so that’s fun.&lt;/p&gt;
&lt;p&gt;One thing doing more art than usual has taught me is that good art, especially really good art is &lt;strong&gt;super hard&lt;/strong&gt; and I totally respect anyone who can do that sort of thing.&lt;/p&gt;
&lt;p&gt;I’ll still definitely stick with programming and computer things (because I love it) but art I think is a good secondary thing to have going.&lt;/p&gt;
&lt;p&gt;Will I post any art here? Probably, as soon as I figure out how to clean the metadata. Most stuff is either posted elsewhere already (under a moniker), or hand-drawn, and scanning is a pain. Anyways.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>More Posts?</title><link>https://www.hazelduvall.dev/blog/posts/2019-05-19-more-posts.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-05-19-more-posts.html</guid><pubDate>Sun, 19 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;What’s the point of having a blog if I never use it? So, I thought I might try something: I’ll attempt to post a short thought here every day. Sorry of like Twitter but more personal.&lt;/p&gt;
&lt;p&gt;That’s all I got for now, see ya tomorrow.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item><item><title>OpenCV Chessboard Test</title><link>https://www.hazelduvall.dev/blog/posts/2019-04-08-opencv-chessboard-test.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-04-08-opencv-chessboard-test.html</guid><pubDate>Mon, 08 Apr 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This was for my Computer Vision class. This thing was pretty simple once you understood it all.&lt;/p&gt;
&lt;div&gt;
&lt;figure&gt;&lt;/figure&gt;
The cube is drawn in perspective on the chessboard
&lt;/div&gt;
&lt;p&gt;The hardest part was getting the chessboard pattern even when the tissue was obscuring part of it. That could be solved by finding the closest point from the previous frame, only taking the ones with a certain min distance, and calling &lt;code&gt;cv::solvePnP&lt;/code&gt; on the filtered chessboard pattern.&lt;/p&gt;
&lt;p&gt;The next challenge is to do the same thing without the chessboard, but it’s pretty hard. Links for future reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://users.ics.forth.gr/~lourakis/levmar/index.html&quot;&gt;http://users.ics.forth.gr/~lourakis/levmar/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://people.eecs.berkeley.edu/~yang/courses/cs294-6/papers/TomasiC_Shape%20and%20motion%20from%20image%20streams%20under%20orthography.pdf&quot;&gt;https://people.eecs.berkeley.edu/~yang/courses/cs294-6/papers/TomasiC_Shape%20and%20motion%20from%20image%20streams%20under%20orthography.pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>projects</category><category>Computer Vision</category><category>TJHSST</category></item><item><title>The Othello Server</title><link>https://www.hazelduvall.dev/blog/posts/2019-04-01-the-othello-server.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-04-01-the-othello-server.html</guid><pubDate>Mon, 01 Apr 2019 12:00:00 GMT</pubDate><content:encoded>&lt;h4&gt;Located at &lt;a href=&quot;https://othello.tjhsst.edu/&quot;&gt;https://othello.tjhsst.edu/&lt;/a&gt;&lt;/h4&gt;
&lt;h4&gt;Code at &lt;a href=&quot;https://github.com/hazelduvall/othello_tourney&quot;&gt;https://github.com/hazelduvall/othello_tourney&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I’d thought I’d finally write about my biggest creation so far. This baby has
been developed through hundreds of hours across 3 years now. Aside from a few
awesome webdev components provided by &lt;a href=&quot;https://williamoconnell.me/&quot;&gt;William O’Connell&lt;/a&gt;,
I wrote &lt;strong&gt;all&lt;/strong&gt; the code from scratch.&lt;/p&gt;
&lt;h3&gt;Background&lt;/h3&gt;
&lt;p&gt;The reason for the Othello Server’s existence starts in TJHSST’s Artificial Intelligence class. Every year, students in the class are assigned to write an AI program that plays the board game Othello. When I took the class, no one actually knew how to test their AI. All we were given was a simple shell to play the AI ourselves through a console window. Sharing your code with others was difficult, involving flash drives and lost programming time.&lt;/p&gt;
&lt;p&gt;So, when I had finished my own AI early, my teacher and I came up with a plan. As an extra-credit project, I would create a simple web platform for students to upload their code to, allowing them to quickly test their code against their classmates’.&lt;/p&gt;
&lt;p&gt;Apparently, I underestimated how much work it would take.&lt;/p&gt;
&lt;h3&gt;The Design&lt;/h3&gt;
&lt;p&gt;Evolution of the Othello Server frontend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Application that generated series of PNGs with PyGame&lt;/li&gt;
&lt;li&gt;Javascript canvas, SocketIO, everything is rectangles&lt;/li&gt;
&lt;li&gt;Javascript canvas, Websockets, and animated pieces&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Evolution of the Othello Server backend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Running it on the same machine&lt;/li&gt;
&lt;li&gt;Running it remotely in a jailed process, Flask webserver&lt;/li&gt;
&lt;li&gt;2-stage backend, one to coordinate the web clients (Django) and one to handle running the AIs (custom asyncio).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am only going to explain in detail the current state because oh boy has everything changed a lot.&lt;/p&gt;
&lt;h4&gt;Frontend&lt;/h4&gt;
&lt;p&gt;The frontend uses websocket callbacks to trigger updates to a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element that displays the board. A few other HTML elements display the player names, score, and any error messages thrown by AI.&lt;/p&gt;
&lt;p&gt;In the end, it looks pretty OK if I do say so myself.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://www.hazelduvall.dev/static/othello_server_demo.png&quot; alt=&quot;Image of a running Othello game&quot; /&gt;&lt;figcaption&gt;&lt;em&gt;All the board and stone images were provided by &lt;a href=&quot;https://williamoconnel.me/&quot;&gt;William O&apos;Connell&lt;/a&gt;&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h4&gt;Django&lt;/h4&gt;
&lt;p&gt;Django is a very nice web framework. I feel, though, it was meant for projects a bit bigger than mine. Pretty much the only reason I use it is for easy OAuth support and the best Websocket support. Doing either of those things in Flask was a lot harder and more bug-prone.&lt;/p&gt;
&lt;p&gt;That’s not to say Django is without its bugs, either. Especially with Channels/ASGI, a lot of things that I thought should be obvious and “just work” didn’t, in fact, work. That was one of the major reasons I split up the backend into two parts. As it turns out, handling incoming clients, safely parsing what games they want to run or what games they want to watch, and actually running the games is best left split up.&lt;/p&gt;
&lt;p&gt;Now, for how I actually structured my Django code. Django itself forces a pretty tight scheme already, but I did take some liberties, especially with the game running code placement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;manage.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run_ai_jailed.py&lt;/code&gt; (for running the jailed AIs)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;othello/&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;settings.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ion_secret.py&lt;/code&gt; (contains secret keys, in &lt;code&gt;.gitignore&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;urls.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;routing.py&lt;/code&gt; (ASGI-specific, similar to above)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;asgi.py&lt;/code&gt; and &lt;code&gt;wsgi.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;static/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;templates/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apps/&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auth/&lt;/code&gt; (handles all the user authentication views, integration with the OAuth library)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;users/&lt;/code&gt; (defines the User model. Could be reasonably combined with above)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;games/&lt;/code&gt; (where most of the code lives. Handles interface with clients, game server backend)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gamescheduler/&lt;/code&gt; (where the entire game server code lives)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;students/&lt;/code&gt; (where all the uploaded student code lives)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run_gamescheduler_server.py&lt;/code&gt; (script to start the regular game server)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run_tournament_gamescheduler_server.py&lt;/code&gt; (runs the game server in tournament mode, rejecting any external requests to play)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;csvity_aztr.py&lt;/code&gt; (turns results blob from tournament into a simple csv file)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Asyncio&lt;/h4&gt;
&lt;p&gt;Asyncio is the culmination of the Python development team’s twisted aims to bring about insanity in all programmers who attempt to use it. Something akin to viewing an eldritch abomination is required to fully understand the internal machinations of &lt;code&gt;Future&lt;/code&gt;s, &lt;code&gt;Task&lt;/code&gt;s, &lt;code&gt;coroutine&lt;/code&gt;s, and &lt;code&gt;awaitable&lt;/code&gt;s. Once the knowledge invades, your mind will never be the same.&lt;/p&gt;
&lt;p&gt;Jokes aside, programming something asyncio is seriously tough. Somehow, though, I pulled through in a weekend-long coding trance to get a fully asynchronous, multithreaded, custom protocol server working. The server using a monolithic protocol to keep track of all client states, something channels could never do (it spawns a new &lt;code&gt;Consumer&lt;/code&gt; every time a client connects). Quick example below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; __name__&lt;/span&gt;&lt;span&gt; ==&lt;/span&gt;&lt;span&gt; &quot;__main__&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    loop &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; asyncio.get_event_loop()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    gs &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GameScheduler(loop)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    def&lt;/span&gt;&lt;span&gt; game_scheduler_factory&lt;/span&gt;&lt;span&gt;(): &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; gs&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    coro &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; loop.create_server(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        game_scheduler_factory,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        host&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;SCHEDULER_HOST&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        port&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;SCHEDULER_PORT&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    server &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; loop.run_until_complete(coro)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # Server requests until Ctrl+C is pressed&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    log.info(&lt;/span&gt;&lt;span&gt;&quot;Running server&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    try&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        loop.run_forever()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    except&lt;/span&gt;&lt;span&gt; KeyboardInterrupt&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        pass&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # Close the server&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    log.info(&lt;/span&gt;&lt;span&gt;&quot;Stopping server&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    server.close()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    loop.run_until_complete(server.wait_closed())&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    loop.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ingoring all the stuff about setting up the event loop, let’s focus on how I instantiate the protocol on line 5. Asyncio expects the factory function to either be the class itself (which can be called like a function to create new members of the class) or a function that returns new members of the class with custom parameters. I am lazy and make a function that returns the same object over and over again, so only it is listening for all incoming connections.&lt;/p&gt;
&lt;p&gt;This is so I can handle all the room processing from within one object, not having to rely on Django’s lock-prone ORM. I did encounter a few a lot way too many errors trying to get asyncio to work properly with handling many rooms at a time and their communication pipelines and all, but in the end it chugs along smoothly.&lt;/p&gt;
&lt;h4&gt;Firejail&lt;/h4&gt;
&lt;p&gt;Now for the part I had the least trouble with (surprisingly): sandboxing! Early on, I did my research and came to the conclusion that &lt;a href=&quot;https://firejail.wordpress.com/&quot;&gt;https://firejail.wordpress.com/&lt;/a&gt; was probably the best solution to my problem of how to secure student AIs. It could be run from the command line, easily installed on Linux, and had robust whitelisting and capability limiting support. Here’s the file I use to sandbox AIs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;caps.drop all&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;net none&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;noroot&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;seccomp&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;whitelist /home/othello/www/venv&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;whitelist /home/othello/www/public&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;whitelist /home/othello/www/run_ai_jailed.py&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;whitelist /home/othello/www/run_ai.py&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;whitelist /home/othello/www/Othello_Core.py&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;whitelist /home/othello/www/othello_admin.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simple easy, done, all that’s left is to surpress firejail’s output with the &lt;code&gt;-q&lt;/code&gt; flag so it doesn’t mess up the other IPC I do.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;I don’t really know where I was going with this. I have a lot of other in-code comments about the Othello Server that I will probably add to this post in the future.&lt;/p&gt;
&lt;p&gt;If I had to choose one big takeaway, it’s this: one person can’t write an enterprise-grade app by themselves. They can try, and partially succeed, but it’ll soon become extremely hard to maintain without the help of others.&lt;/p&gt;
&lt;p&gt;I’m hopeful that another Sysadmins at TJHSST will take up my mantle as the lead Othello Server developer after I’m gone. Anyways, thanks for reading if you made it this far.&lt;/p&gt;
&lt;p&gt;TL;DR: Othello Server wack cool&lt;/p&gt;</content:encoded><category>projects</category><category>TJHSST</category></item><item><title>Hello, World!</title><link>https://www.hazelduvall.dev/blog/posts/2019-03-12-hello-world.html</link><guid isPermaLink="true">https://www.hazelduvall.dev/blog/posts/2019-03-12-hello-world.html</guid><pubDate>Tue, 12 Mar 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Might as well start a blog, I guess&lt;/p&gt;
&lt;p&gt;This is running on an old Sony Vaio Laptop, Ubuntu 18.04 LTS. Nothing special, but it gets the job done.&lt;/p&gt;</content:encoded><category>daily thoughts</category></item></channel></rss>